[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: jbachorik\nissuehunt: jbachorik\notechie: # Replace with a single Otechie username\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/copilot-instructions.md",
    "content": "# GitHub Copilot Instructions for BTrace\n\n## About BTrace\nBTrace is a safe, dynamic tracing tool for the Java platform. It dynamically instruments running Java applications to inject tracing code at runtime using bytecode instrumentation.\n\n## Project Structure\n- **Gradle multi-module project** with modules named `btrace-*`\n- **Core modules**: `btrace-core`, `btrace-agent`, `btrace-runtime`, `btrace-client`, `btrace-instr`\n- **Build artifacts**: `btrace-dist` for distributions\n- **Tests**: `integration-tests/` for integration tests, `src/test/java` in modules for unit tests\n- **Documentation**: `docs/` directory\n\n## Architecture Overview\n- **btrace-agent**: Attachable Java agent with class transformer, manages script lifecycle\n- **btrace-compiler**: Verifies and compiles BTrace scripts to bytecode\n- **btrace-instr**: ASM-based instrumentation and weaving utilities\n- **btrace-runtime**: APIs for scripts (printing, timers, data collection)\n- **btrace-client**: CLI/attach tooling for sending scripts to target JVM\n- **services**: SPI for pluggable exporters (e.g., statsd)\n\n## Development Guidelines\n\n### Language & Versions\n- **Language**: Java\n- **Source/Target**: Java 8\n- **Build toolchain**: JDK 11\n- **Test framework**: JUnit Jupiter (JUnit 5)\n\n### Code Style\n- **Format**: Google Java Format enforced via Spotless\n- **Packages**: All under `org.openjdk.btrace.*`\n- **Naming**: Module names follow `btrace-<component>` pattern\n- **Imports**: Order enforced; remove unused imports\n- **Comments**: Only add if they match existing style or explain complex logic\n\n### Building & Testing\n```bash\n# Full build with unit tests\n./gradlew build\n\n# Build distribution only\n./gradlew :btrace-dist:build\n\n# Run unit tests\n./gradlew test\n\n# Run integration tests (requires dist build first)\n./gradlew -Pintegration test\n\n# Format code\n./gradlew spotlessApply\n\n# Check formatting\n./gradlew spotlessCheck\n```\n\n### Important Environment Variables\n- `JAVA_HOME`: Required for builds\n- `TEST_JAVA_HOME`: Required for integration tests (typically JDK 11)\n- `BTRACE_TEST_DEBUG=true`: Enable verbose integration test output\n- `BTRACE_HOME`: Optional, points to exploded dist\n\n### Testing Best Practices\n- Unit tests: `src/test/java` with `*Test` suffix\n- Integration tests: `integration-tests/src/test/java`\n- BTrace scripts: `integration-tests/src/test/btrace`\n- Always run relevant tests after making changes\n- Update golden files when changing instrumentor: `./gradlew test -PupdateTestData`\n\n### Commit & PR Guidelines\n- **Commit style**: Conventional Commits (e.g., `feat(core): add probe`, `fix(instr): handle null arg`)\n- **Clear descriptions**: Link related issues\n- **Tests required**: Update/add tests; ensure CI passes\n- **Formatting**: Must pass `spotlessCheck`\n- **No unrelated changes**: Keep changes focused and minimal\n\n## Troubleshooting\n\n### Build Issues\n- **Attach disabled**: Remove `-XX:+DisableAttachMechanism` from target JVM\n- **Permission errors**: Attach requires same OS user as target JVM\n- **Toolchain issues**: Verify `JAVA_HOME` and `TEST_JAVA_HOME` point to valid JDKs\n\n### Restricted Environments\n```bash\n# Use workspace-local Gradle cache\nGRADLE_USER_HOME=$(pwd)/.gradle-user\n\n# Force IPv4 to avoid network interface issues\nJAVA_TOOL_OPTIONS=\"-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false\"\n```\n\n## Code Generation Tips\n- **Prefer simplicity**: Simple, performant solutions over complex designs\n- **Use existing patterns**: Follow patterns from similar code in the repository\n- **Minimal changes**: Make the smallest possible changes to achieve the goal\n- **Reuse libraries**: Use ASM for bytecode, JCTools for concurrency, existing BTrace APIs\n- **No temporary files in repo**: Use `/tmp` for scratch work\n- **Security**: Never commit secrets; avoid introducing vulnerabilities\n\n## Example BTrace Script Pattern\n```java\npackage example;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\nimport org.openjdk.btrace.core.annotations.*;\n\n@BTrace\npublic class ExampleTrace {\n  @OnMethod(clazz=\"com.example.Target\", method=\"methodName\")\n  public static void onMethod(@ProbeMethodName String method) {\n    println(\"Called: \" + method);\n  }\n}\n```\n\n## Key Dependencies\n- **ASM**: Bytecode manipulation\n- **JCTools**: High-performance concurrent data structures\n- **hppcrt**: Optimized collections\n- **JUnit Jupiter**: Testing framework\n\n## Additional Resources\n- Full guidelines: See `AGENTS.md` in repository root\n- Tutorial: `docs/BTraceTutorial.md`\n- Binary releases: https://github.com/btraceio/btrace/releases\n"
  },
  {
    "path": ".github/workflows/README.md",
    "content": "# BTrace GitHub Actions Workflows\n\n## Overview\n\nThis directory contains GitHub Actions workflows for continuous integration and testing of the BTrace project, with special focus on the new Binary Protocol v2 implementation.\n\n## Workflows\n\n### 1. `continuous.yml` - Main CI/CD Pipeline\n\n**Purpose:** Main continuous integration pipeline for all BTrace components.\n\n**Triggers:**\n- Push to `develop` branch\n- Pull requests to `develop`\n- Manual workflow dispatch\n\n**Jobs:**\n- **build:** Compiles the project and runs all tests\n  - Java 11 with Temurin distribution\n  - Parallel build with caching\n  - **V2 Protocol Tests:** Runs dedicated v2 protocol test suite\n  - Uploads dist build artifacts\n- **test:** Runs integration tests on multiple Java versions\n  - Matrix: Java 8, 11, 17, 21, 25 (EA)\n  - Uses SDKMAN for multiple JDK management\n  - Downloads build artifacts from previous job\n  - Runs integration tests with `-Pintegration` flag\n- **publish:** Publishes artifacts to Maven Central\n  - Only on `develop` branch\n  - Requires GPG signing credentials\n- **cleanup:** Removes temporary artifacts\n\n**Enhancements for V2 Protocol:**\n- Added explicit V2 protocol test execution in build job\n- Tests all v2 packages: `v2.*`, `Protocol*`, `WireProtocol*`\n\n### 2. `v2-protocol-tests.yml` - V2 Protocol Test Suite\n\n**Purpose:** Comprehensive testing suite specifically for Binary Protocol v2.\n\n**Triggers:**\n- Push to `develop`, `master`, or `jb/comm_v2` branches\n- Pull requests to `develop`\n- Changes to protocol-related files\n- Manual workflow dispatch\n- Commit messages containing `[benchmark]`\n\n**Jobs:**\n\n#### **unit-tests**\n- Runs all v2 protocol unit tests on Java 11, 17, 21\n- Tests binary serialization/deserialization\n- Validates all 17 command types\n- Upload test reports as artifacts\n\n#### **protocol-negotiation-tests**\n- Tests protocol version detection\n- Validates V1/V2 negotiation\n- Tests configuration management\n- Verifies magic byte detection\n\n#### **edge-case-tests**\n- Runs 35 edge case scenarios\n- Tests boundary conditions\n- Validates large message handling\n- Tests compression functionality\n- Unicode and special character handling\n\n#### **jmh-benchmarks** (Manual/Opt-in)\n- Runs JMH performance benchmarks\n- Triggered by workflow dispatch or `[benchmark]` in commit message\n- Quick benchmarks: warmup=1, iterations=2, fork=1\n- Focuses on serialization performance\n- Uploads JMH results for 30 days\n\n#### **protocol-compatibility**\n- Tests all 4 compatibility scenarios:\n  - V2 client ↔ V2 agent (optimal)\n  - V1 client ↔ V1 agent (legacy)\n  - V2 client ↔ V1 agent (fallback)\n  - V1 client ↔ V2 agent (detection)\n- Matrix strategy for comprehensive coverage\n- Validates backward compatibility\n\n#### **test-summary**\n- Aggregates test results from all jobs\n- Generates GitHub Step Summary\n- Reports total/passed/failed counts\n- Fails if any tests failed\n\n#### **code-coverage**\n- Generates JaCoCo coverage reports\n- Focuses on `org.openjdk.btrace.core.comm` package\n- Uploads coverage artifacts for 30 days\n- Creates coverage summary in step output\n\n### 3. `codeql-analysis.yml` - Security Analysis\n\n**Purpose:** CodeQL security scanning for vulnerability detection.\n\n**Triggers:** Push/PR to default branch\n\n### 4. `stale.yml` - Issue Management\n\n**Purpose:** Automatically marks stale issues and PRs.\n\n**Schedule:** Daily at midnight\n\n### 5. `release.yml` - Release Management\n\n**Purpose:** Handles the complete release process with a manual checkpoint for Maven Central.\n\n**Trigger:** Manual via `scripts/release.sh` or workflow_dispatch\n\n**Key Features:**\n- Stages artifacts to Maven Central (does NOT auto-release)\n- Waits up to 30 minutes for manual release via Central Portal\n- Creates GitHub release only after Maven artifacts are available\n- Updates SDKMan and manages milestones\n\n**Manual Checkpoint:** After staging, you must release via [Central Portal](https://central.sonatype.com/publishing/deployments). This allows reviewing artifacts before they become permanent.\n\n## V2 Protocol Test Coverage\n\nThe workflows ensure comprehensive testing of the v2 protocol implementation:\n\n### Unit Tests (113 total)\n- ✅ Binary protocol serialization (26 tests)\n- ✅ Edge cases and boundaries (35 tests)\n- ✅ Performance comparison (2 tests)\n- ✅ Protocol negotiation (16 tests)\n- ✅ Configuration management (18 tests)\n- ✅ WireProtocol abstraction (16 tests)\n\n### Test Categories\n1. **Command Serialization**\n   - All 17 BTrace command types\n   - Round-trip serialization/deserialization\n   - Compression testing\n\n2. **Protocol Negotiation**\n   - V1/V2 auto-detection\n   - Magic byte validation\n   - Configuration-based selection\n   - Stream handling (pushback & mark/reset)\n\n3. **Edge Cases**\n   - Null/empty values\n   - Large messages (10MB)\n   - Unicode and emojis\n   - Malformed data\n   - Numeric boundaries\n\n4. **Performance**\n   - JMH benchmarks (180 configurations)\n   - V1 vs V2 comparison\n   - Compression effectiveness\n\n5. **Compatibility**\n   - V1 ↔ V1 (legacy)\n   - V2 ↔ V2 (optimal)\n   - V1 ↔ V2 (cross-version)\n   - V2 ↔ V1 (fallback)\n\n## Artifacts\n\n### Retained Artifacts (7 days)\n- Test reports (per Java version)\n- Negotiation test results\n- Edge case test results\n- Compatibility test matrices\n\n### Long-term Artifacts (30 days)\n- JMH benchmark results\n- Code coverage reports\n\n### Build Artifacts (1 day)\n- Distribution builds\n- Test trace data\n\n## Configuration\n\n### Environment Variables\n\n**Build Job:**\n- Standard Gradle environment\n- Parallel execution enabled\n- Build cache enabled\n\n**Test Job:**\n- `TEST_JAVA_HOME`: Set per matrix Java version\n- SDKMAN for multiple JDK management\n\n**Publish Job:**\n- `GPG_SIGNING_KEY`: GPG key for artifact signing\n- `GPG_SIGNING_PWD`: GPG key password\n- `BTRACE_SONATYPE_USER`: Sonatype credentials\n- `BTRACE_SONATYPE_PWD`: Sonatype credentials\n\n### Gradle Properties for V2 Testing\n\n```bash\n# Run only v2 tests\n./gradlew :btrace-core:test --tests \"org.openjdk.btrace.core.comm.v2.*\"\n\n# Run protocol negotiation tests\n./gradlew :btrace-core:test --tests \"*Protocol*\"\n\n# Run specific JMH benchmarks\n./gradlew :btrace-core:jmh -PjmhInclude=\".*MessageCommand.*\"\n\n# Generate coverage report\n./gradlew :btrace-core:test jacocoTestReport\n```\n\n## JMH Benchmark Workflow\n\n### Trigger Benchmark Run\n\n**Option 1: Workflow Dispatch**\n```bash\n# Via GitHub UI: Actions → V2 Protocol Tests → Run workflow\n```\n\n**Option 2: Commit Message**\n```bash\ngit commit -m \"Optimize binary protocol [benchmark]\"\n```\n\n### Benchmark Configuration\n\n**Quick Benchmarks (CI):**\n- Warmup: 1 iteration\n- Measurement: 2 iterations\n- Forks: 1\n- Focus: Serialization methods only\n\n**Full Benchmarks (Local):**\n- Warmup: 3 iterations\n- Measurement: 5 iterations\n- Forks: 2\n- Coverage: All 180 configurations\n\n## Test Failure Handling\n\n### Automatic Retry\n- Tests use `--rerun-tasks` to ensure fresh execution\n- No test result caching to catch flaky tests\n\n### Artifact Upload\n- All test reports uploaded on failure (`if: always()`)\n- Artifacts retained for 7 days for analysis\n\n### Summary Generation\n- Test summary job aggregates all results\n- Reports failures clearly in GitHub UI\n- Step summary provides quick overview\n\n## Code Coverage\n\n### JaCoCo Configuration\n\n**Focus Area:**\n- Package: `org.openjdk.btrace.core.comm.**`\n- Includes v2 protocol, negotiation, and abstraction\n\n**Reports Generated:**\n- XML (for CI tools)\n- HTML (for human review)\n- Available in artifacts for 30 days\n\n**Coverage Goals:**\n- Unit test coverage: >90%\n- Edge case coverage: >80%\n- Integration coverage: >70%\n\n## Performance Monitoring\n\n### JMH Results\n- Benchmark results uploaded as artifacts\n- Compare across runs to detect regressions\n- Focus on serialization/deserialization speed\n- Monitor wire size changes\n\n### Expected Metrics\n- Serialization: 3-6x faster than V1\n- Wire size: 2-5x smaller than V1\n- Compression: 10-100x size reduction (large messages)\n\n## Maintenance\n\n### Cache Management\n- Gradle cache keyed by build files hash\n- Automatic cache eviction after 7 days\n- Cache size monitored in test job\n\n### Artifact Cleanup\n- Temporary artifacts cleaned after publish\n- Test reports retained for 7 days\n- Performance results retained for 30 days\n\n## Future Enhancements\n\n### Planned Additions\n1. **Integration Tests:**\n   - Full client-agent communication tests\n   - Mixed protocol version scenarios\n   - Reconnection testing\n\n2. **Stress Tests:**\n   - High concurrency scenarios\n   - Large message throughput\n   - Memory leak detection\n\n3. **Performance Regression Detection:**\n   - Automated benchmark comparison\n   - Alert on >10% performance degradation\n   - Historical trend analysis\n\n4. **Security Scanning:**\n   - Dependency vulnerability checks\n   - OWASP security analysis\n   - Protocol fuzzing tests\n\n## References\n\n- [BTrace v2 Protocol Architecture](../../docs/architecture/Version2ProtocolArchitecture.md)\n- [Phase 3 Integration Guide](../../docs/architecture/phase3-integration-guide.md)\n- [V2 Implementation Summary](../../docs/architecture/v2-implementation-summary.md)\n- [JMH Benchmarks Guide](../../btrace-core/JMH_BENCHMARKS.md)\n\n## Support\n\nFor workflow issues or questions:\n1. Check GitHub Actions logs\n2. Review artifact contents\n3. Check Gradle build logs\n4. Open issue with workflow run link\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [ develop, master ]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ develop ]\n  schedule:\n    - cron: '23 5 * * 4'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'java' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]\n        # Learn more about CodeQL language support at https://git.io/codeql-language-support\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v6\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v4\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    - name: Build BTrace\n      run: |\n        ./gradlew -x test build\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v4\n"
  },
  {
    "path": ".github/workflows/continuous.yml",
    "content": "# This workflow will build a Java project with Gradle\n# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle\n\nname: BTrace CI/CD\n\non:\n  push:\n    branches: [ develop ]\n  pull_request:\n    branches: [ develop ]\n  workflow_dispatch:\n\ndefaults:\n  run:\n    shell: bash\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Cache Java binaries\n        id: cache-java\n        uses: actions/cache@v5\n        with:\n          path: ${{ runner.tool_cache }}/Java_*\n          key: java-${{ runner.os }}-temurin-11\n      - name: Set up Java\n        if: steps.cache-java.outputs.cache-hit != 'true'\n        uses: actions/setup-java@v5\n        with:\n          java-version: 11\n          distribution: temurin\n      - name: Checkout\n        uses: actions/checkout@v6\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n      - name: Generate cache key\n        id: cache-key\n        run: |\n          key=\"${{ runner.os }}-gradle-1-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}\"\n          echo \"key=${key}\" >> $GITHUB_ENV\n          echo \"cache-key=${key}\" >> $GITHUB_OUTPUT\n      - name: Cache Gradle\n        uses: actions/cache@v5\n        with:\n          path: |\n            ~/.gradle/caches/modules-2\n            ~/.gradle/wrapper\n          key: ${{ env.key }}\n          restore-keys: |\n            ${{ runner.os }}-gradle-\n      - name: Build\n        run: ./gradlew --no-daemon --parallel --build-cache build\n      - name: Run V2 Protocol Tests\n        run: |\n          ./gradlew :btrace-core:test --tests \"org.openjdk.btrace.core.comm.v2.*\" \\\n                                       --tests \"org.openjdk.btrace.core.comm.Protocol*\" \\\n                                       --tests \"org.openjdk.btrace.core.comm.WireProtocol*\"\n      - name: Upload dist build data\n        if: always()\n        uses: actions/upload-artifact@v7\n        with:\n          name: dist-build\n          retention-days: 1\n          path: |\n            btrace-dist/build\n            btrace-instr/build/classes/traces\n      - name: Upload test trace data\n        if: always()\n        uses: actions/upload-artifact@v7\n        with:\n          name: test-trace\n          retention-days: 1\n          path: |\n            btrace-instr/build/classes/traces\n      - name: Archive test reports\n        if: always()\n        uses: actions/upload-artifact@v7\n        with:\n          name: test-reports\n          path: |\n            **/reports/**/*\n    outputs:\n      cache-key: ${{ steps.cache-key.outputs.cache-key }}\n\n  test:\n    needs: build\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    strategy:\n      fail-fast: false\n      matrix:\n        java: [ 8.0.482-tem, 11.0.30-tem, 17.0.18-tem, 21.0.10-tem, 25.0.2-tem, 26.ea.35-open ]\n    env:\n      TEST_JAVA_HOME: \"/home/runner/.sdkman/candidates/java/${{ matrix.java }}\"\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n      - name: Prepare OS\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y curl zip unzip\n      - name: Prepare JDK ${{ matrix.java_version }}\n        run: |\n          curl -s \"https://get.sdkman.io\" | bash\n          source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n          echo 'n' | sdk install java ${{ matrix.java }}\n          which java\n          echo 'y' | sdk install java 11.0.30-tem\n      - name: Cache Gradle\n        uses: actions/cache@v5\n        with:\n          path: |\n            ~/.gradle/caches/modules-2\n            ~/.gradle/wrapper\n          key: ${{ needs.build.outputs.cache-key }}\n          restore-keys: |\n            ${{ runner.os }}-gradle-\n      - name: Download build data\n        uses: actions/download-artifact@v8\n        with:\n          name: dist-build\n          path: btrace-dist/build\n      - name: Download test trace data\n        uses: actions/download-artifact@v8\n        with:\n          name: test-trace\n          path: btrace-instr/build/classes/traces\n      - name: Build btrace-instr jar\n        run: |\n          ./gradlew --no-daemon --parallel --build-cache :btrace-instr:jar\n      - name: Run tests\n        run: |\n          set +x\n          ./gradlew --no-daemon --parallel --build-cache -Pintegration -PCI :integration-tests:test\n      - name: Check Gradle cache size\n        run: du -sh ~/.gradle/caches\n      - name: Integration test reports\n        if: always()\n        uses: actions/upload-artifact@v7\n        with:\n          name: integration-test-reports-${{ matrix.java }}\n          path: |\n            integration-tests/build/reports/**/*\n      - name: Archive binary artifacts\n        if: success() && matrix.java == '11'\n        uses: actions/upload-artifact@v7\n        with:\n          name: btrace-dist\n          path: |\n            btrace-dist/build/distributions/**/btrace-*-bin*.tar.gz\n\n  publish:\n    if: github.ref == 'refs/heads/develop'\n    needs: \n      - test\n      - build\n    runs-on: ubuntu-latest\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v6\n    - name: Grant execute permission for gradlew\n      run: chmod +x gradlew\n    - name: Setup Gradle\n      uses: gradle/actions/setup-gradle@v6\n    - name: Cache Java binaries\n      id: cache-java\n      uses: actions/cache@v5\n      with:\n        path: ${{ runner.tool_cache }}/Java_*\n        key: java-${{ runner.os }}-temurin-11\n    - name: Set up Java\n      if: steps.cache-java.outputs.cache-hit != 'true'\n      uses: actions/setup-java@v5\n      with:\n        java-version: 11\n        distribution: temurin\n    - name: Cache Gradle\n      uses: actions/cache@v5\n      with:\n        path: |\n          ~/.gradle/caches/modules-2\n          ~/.gradle/wrapper\n        key: ${{ needs.build.outputs.cache-key }}\n        restore-keys: |\n          ${{ runner.os }}-gradle-\n    - name: Download build data\n      uses: actions/download-artifact@v8\n      with:\n        name: dist-build\n    - name: Deploy Maven\n      run: ./gradlew -x test :btrace-dist:publish\n      env:\n        GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}\n        GPG_SIGNING_PWD: ${{ secrets.GPG_SIGNING_PWD }}\n        SONATYPE_USER: ${{ secrets.SONATYPE_USERNAME }}\n        SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}\n\n  cleanup:\n    runs-on: ubuntu-latest\n    needs: publish\n    steps:\n      - name: Cleanup temporary artifacts\n        uses: geekyeggo/delete-artifact@v6\n        with:\n          name: dist-build\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "# BTrace Release Workflow\n#\n# This workflow handles the complete release process:\n# 1. Validates inputs and prerequisites\n# 2. Runs full test suite (unit + integration tests)\n# 3. Creates release branch and tag\n# 4. Stages artifacts to Maven Central (requires manual release)\n# 5. Waits for Maven Central availability (up to 30 minutes)\n# 6. Creates GitHub release with artifacts\n# 7. Updates SDKMan\n# 8. Updates version numbers for next development cycle\n# 9. Manages milestones\n#\n# IMPORTANT: Maven artifacts are STAGED, not released automatically.\n# After staging, go to https://central.sonatype.com/publishing/deployments\n# to review and release. The workflow will wait up to 30 minutes.\n#\n# Triggered by scripts/release.sh or manually via workflow_dispatch\n\nname: Release\n\non:\n  workflow_dispatch:\n    inputs:\n      release_type:\n        description: 'Release type'\n        required: true\n        type: choice\n        options:\n          - major\n          - minor\n          - patch\n      release_version:\n        description: 'Release version (e.g., 2.3.0)'\n        required: true\n        type: string\n      commit_sha:\n        description: 'Source commit SHA'\n        required: true\n        type: string\n      release_branch:\n        description: 'Release branch (e.g., release/2.3._)'\n        required: true\n        type: string\n      next_snapshot:\n        description: 'Next snapshot version (e.g., 2.4.0-SNAPSHOT)'\n        required: true\n        type: string\n      dry_run:\n        description: 'Dry run (skip publishing and tagging)'\n        required: false\n        type: boolean\n        default: false\n\ndefaults:\n  run:\n    shell: bash\n\nenv:\n  RELEASE_VERSION: ${{ inputs.release_version }}\n  RELEASE_TAG: v${{ inputs.release_version }}\n  RC_TAG: v${{ inputs.release_version }}_RC\n\njobs:\n  # ============================================================\n  # Job 1: Validate inputs and prerequisites\n  # ============================================================\n  validate:\n    name: Validate Release\n    runs-on: ubuntu-latest\n    outputs:\n      branch_exists: ${{ steps.check-branch.outputs.exists }}\n      create_branch: ${{ steps.check-branch.outputs.create }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ inputs.commit_sha }}\n          fetch-depth: 0\n\n      - name: Validate inputs\n        run: |\n          echo \"Validating release inputs...\"\n          echo \"  Release Type: ${{ inputs.release_type }}\"\n          echo \"  Release Version: ${{ inputs.release_version }}\"\n          echo \"  Commit SHA: ${{ inputs.commit_sha }}\"\n          echo \"  Release Branch: ${{ inputs.release_branch }}\"\n          echo \"  Next Snapshot: ${{ inputs.next_snapshot }}\"\n          echo \"  Dry Run: ${{ inputs.dry_run }}\"\n\n          # Validate version format (X.Y.Z)\n          if [[ ! \"${{ inputs.release_version }}\" =~ ^[0-9]+\\.[0-9]+\\.[0-9]+$ ]]; then\n            echo \"::error::Invalid version format. Expected X.Y.Z\"\n            exit 1\n          fi\n\n          # Validate release type\n          if [[ ! \"${{ inputs.release_type }}\" =~ ^(major|minor|patch)$ ]]; then\n            echo \"::error::Invalid release type. Expected major, minor, or patch\"\n            exit 1\n          fi\n\n          # Validate commit exists\n          if ! git cat-file -e \"${{ inputs.commit_sha }}^{commit}\" 2>/dev/null; then\n            echo \"::error::Commit ${{ inputs.commit_sha }} does not exist\"\n            exit 1\n          fi\n\n          echo \"All inputs validated successfully\"\n\n      - name: Check if tag exists\n        run: |\n          if git rev-parse \"v${{ inputs.release_version }}\" >/dev/null 2>&1; then\n            echo \"::error::Tag v${{ inputs.release_version }} already exists\"\n            exit 1\n          fi\n          if git ls-remote --tags origin \"refs/tags/v${{ inputs.release_version }}\" | grep -q .; then\n            echo \"::error::Tag v${{ inputs.release_version }} already exists on remote\"\n            exit 1\n          fi\n          # Check for leftover RC tag\n          if git rev-parse \"${RC_TAG}\" >/dev/null 2>&1; then\n            echo \"::error::RC tag ${RC_TAG} already exists locally. Clean up with: git tag -d ${RC_TAG}\"\n            exit 1\n          fi\n          if git ls-remote --tags origin \"refs/tags/${RC_TAG}\" | grep -q .; then\n            echo \"::error::RC tag ${RC_TAG} already exists on remote. Clean up with: git push origin :refs/tags/${RC_TAG}\"\n            exit 1\n          fi\n          echo \"Tag does not exist - OK\"\n\n      - name: Check if release branch exists\n        id: check-branch\n        run: |\n          BRANCH=\"${{ inputs.release_branch }}\"\n          if git show-ref --verify --quiet \"refs/remotes/origin/${BRANCH}\"; then\n            echo \"Release branch ${BRANCH} already exists\"\n            echo \"exists=true\" >> $GITHUB_OUTPUT\n            echo \"create=false\" >> $GITHUB_OUTPUT\n          else\n            echo \"Release branch ${BRANCH} will be created\"\n            echo \"exists=false\" >> $GITHUB_OUTPUT\n            echo \"create=true\" >> $GITHUB_OUTPUT\n          fi\n\n  # ============================================================\n  # Job 2: Build and run unit tests\n  # ============================================================\n  build-and-test:\n    name: Build and Test\n    needs: validate\n    runs-on: ubuntu-latest\n    outputs:\n      cache-key: ${{ steps.cache-key.outputs.key }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ inputs.commit_sha }}\n\n      - name: Cache Java binaries\n        id: cache-java\n        uses: actions/cache@v5\n        with:\n          path: ${{ runner.tool_cache }}/Java_*\n          key: java-${{ runner.os }}-temurin-11\n\n      - name: Set up Java\n        if: steps.cache-java.outputs.cache-hit != 'true'\n        uses: actions/setup-java@v5\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n\n      - name: Generate cache key\n        id: cache-key\n        run: |\n          key=\"${{ runner.os }}-gradle-release-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}\"\n          echo \"key=${key}\" >> $GITHUB_OUTPUT\n\n      - name: Cache Gradle\n        uses: actions/cache@v5\n        with:\n          path: |\n            ~/.gradle/caches/modules-2\n            ~/.gradle/wrapper\n          key: ${{ steps.cache-key.outputs.key }}\n          restore-keys: |\n            ${{ runner.os }}-gradle-\n\n      - name: Build\n        run: ./gradlew --no-daemon --parallel --build-cache build\n\n      - name: Upload dist build data\n        uses: actions/upload-artifact@v7\n        with:\n          name: dist-build\n          retention-days: 1\n          path: |\n            btrace-dist/build\n            btrace-instr/build/classes/traces\n\n      - name: Upload test trace data\n        uses: actions/upload-artifact@v7\n        with:\n          name: test-trace\n          retention-days: 1\n          path: |\n            btrace-instr/build/classes/traces\n\n      - name: Archive test reports\n        if: always()\n        uses: actions/upload-artifact@v7\n        with:\n          name: unit-test-reports\n          path: |\n            **/reports/**/*\n\n  # ============================================================\n  # Job 3: Integration tests on multiple JDK versions\n  # ============================================================\n  integration-tests:\n    name: Integration Tests (JDK ${{ matrix.java }})\n    needs: build-and-test\n    runs-on: ubuntu-latest\n    timeout-minutes: 15\n    strategy:\n      fail-fast: false\n      matrix:\n        java: [8.0.482-tem, 11.0.30-tem, 17.0.18-tem, 21.0.10-tem]\n    env:\n      TEST_JAVA_HOME: \"/home/runner/.sdkman/candidates/java/${{ matrix.java }}\"\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ inputs.commit_sha }}\n\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n\n      - name: Prepare OS\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y curl zip unzip\n\n      - name: Prepare JDK ${{ matrix.java }}\n        run: |\n          curl -s \"https://get.sdkman.io\" | bash\n          source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n          echo 'n' | sdk install java ${{ matrix.java }}\n          which java\n          echo 'y' | sdk install java 11.0.30-tem\n\n      - name: Cache Gradle\n        uses: actions/cache@v5\n        with:\n          path: |\n            ~/.gradle/caches/modules-2\n            ~/.gradle/wrapper\n          key: ${{ needs.build-and-test.outputs.cache-key }}\n          restore-keys: |\n            ${{ runner.os }}-gradle-\n\n      - name: Download build data\n        uses: actions/download-artifact@v8\n        with:\n          name: dist-build\n          path: btrace-dist/build\n\n      - name: Download test trace data\n        uses: actions/download-artifact@v8\n        with:\n          name: test-trace\n          path: btrace-instr/build/classes/traces\n\n      - name: Build btrace-instr jar\n        run: |\n          ./gradlew --no-daemon --parallel --build-cache :btrace-instr:jar\n\n      - name: Run integration tests\n        run: |\n          ./gradlew --no-daemon --parallel --build-cache -Pintegration :integration-tests:test\n\n      - name: Integration test reports\n        if: always()\n        uses: actions/upload-artifact@v7\n        with:\n          name: integration-test-reports-${{ matrix.java }}\n          path: |\n            integration-tests/build/reports/**/*\n\n  # ============================================================\n  # Job 4: Prepare release (create branch, update version, tag)\n  # ============================================================\n  prepare-release:\n    name: Prepare Release\n    needs: [validate, integration-tests]\n    runs-on: ubuntu-latest\n    outputs:\n      release_sha: ${{ steps.commit.outputs.sha }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ inputs.commit_sha }}\n          fetch-depth: 0\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Configure Git\n        run: |\n          git config user.name \"github-actions[bot]\"\n          git config user.email \"github-actions[bot]@users.noreply.github.com\"\n\n      - name: Create or checkout release branch\n        run: |\n          BRANCH=\"${{ inputs.release_branch }}\"\n          if git show-ref --verify --quiet \"refs/remotes/origin/${BRANCH}\"; then\n            echo \"Checking out existing branch ${BRANCH}\"\n            git checkout -b \"${BRANCH}\" \"origin/${BRANCH}\"\n          else\n            echo \"Creating new branch ${BRANCH}\"\n            git checkout -b \"${BRANCH}\"\n          fi\n\n      - name: Update version in build.gradle\n        run: |\n          VERSION=\"${{ inputs.release_version }}\"\n          sed -i \"s/version = '.*'/version = '${VERSION}'/\" build.gradle\n          echo \"Updated version to ${VERSION}\"\n          grep \"version = \" build.gradle\n\n      - name: Commit version change\n        id: commit\n        run: |\n          git add build.gradle\n          git commit -m \"Release ${RELEASE_TAG}\"\n          SHA=$(git rev-parse HEAD)\n          echo \"sha=${SHA}\" >> $GITHUB_OUTPUT\n          echo \"Release commit: ${SHA}\"\n\n      - name: Create RC tag\n        if: ${{ inputs.dry_run != true }}\n        run: |\n          git tag -a \"${RC_TAG}\" -m \"Release candidate ${RELEASE_TAG}\"\n          echo \"Created RC tag ${RC_TAG}\"\n\n      - name: Push branch and RC tag\n        if: ${{ inputs.dry_run != true }}\n        run: |\n          git push origin \"${{ inputs.release_branch }}\"\n          git push origin \"${RC_TAG}\"\n          echo \"Pushed branch and RC tag\"\n\n      - name: Dry run summary\n        if: ${{ inputs.dry_run == true }}\n        run: |\n          echo \"::warning::DRY RUN - Branch and tag NOT pushed\"\n          echo \"Would have pushed:\"\n          echo \"  - Branch: ${{ inputs.release_branch }}\"\n          echo \"  - RC Tag: ${RC_TAG}\"\n\n  # ============================================================\n  # Job 5: Stage to Maven Central (does NOT release)\n  # ============================================================\n  stage-maven:\n    name: Stage to Maven Central\n    needs: [prepare-release, build-and-test]\n    runs-on: ubuntu-latest\n    if: ${{ inputs.dry_run != true }}\n    steps:\n      - name: Checkout RC tag\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ env.RC_TAG }}\n\n      - name: Cache Java binaries\n        id: cache-java\n        uses: actions/cache@v5\n        with:\n          path: ${{ runner.tool_cache }}/Java_*\n          key: java-${{ runner.os }}-temurin-11\n\n      - name: Set up Java\n        if: steps.cache-java.outputs.cache-hit != 'true'\n        uses: actions/setup-java@v5\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n\n      - name: Cache Gradle\n        uses: actions/cache@v5\n        with:\n          path: |\n            ~/.gradle/caches/modules-2\n            ~/.gradle/wrapper\n          key: ${{ needs.build-and-test.outputs.cache-key }}\n          restore-keys: |\n            ${{ runner.os }}-gradle-\n\n      - name: Stage to Maven Central\n        env:\n          GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}\n          GPG_SIGNING_PWD: ${{ secrets.GPG_SIGNING_PWD }}\n          SONATYPE_USER: ${{ secrets.SONATYPE_USERNAME }}\n          SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}\n        run: |\n          echo \"Staging artifacts to Central Portal...\"\n          echo \"After this job completes, go to https://central.sonatype.com/publishing/deployments\"\n          echo \"to review and release the staged artifacts.\"\n          ./gradlew :btrace-dist:publishAllPublicationsToSonatypeRepository --no-daemon\n\n      - name: Staging complete\n        run: |\n          echo \"==============================================\"\n          echo \"ARTIFACTS STAGED - MANUAL RELEASE REQUIRED\"\n          echo \"==============================================\"\n          echo \"\"\n          echo \"Staged artifacts:\"\n          echo \"  - io.btrace:btrace-agent:${{ inputs.release_version }}\"\n          echo \"  - io.btrace:btrace-client:${{ inputs.release_version }}\"\n          echo \"  - io.btrace:btrace-boot:${{ inputs.release_version }}\"\n          echo \"\"\n          echo \"Next steps:\"\n          echo \"  1. Go to https://central.sonatype.com/publishing/deployments\"\n          echo \"  2. Review the staged repository\"\n          echo \"  3. Click 'Publish' to release to Maven Central\"\n          echo \"\"\n          echo \"The workflow will wait up to 30 minutes for artifacts to appear.\"\n          echo \"If you don't want to proceed, let the workflow timeout or cancel it.\"\n\n  # ============================================================\n  # Job 5b: Wait for Maven Central availability\n  # ============================================================\n  wait-for-maven:\n    name: Wait for Maven Central\n    needs: stage-maven\n    runs-on: ubuntu-latest\n    timeout-minutes: 35\n    steps:\n      - name: Wait for artifacts on Maven Central\n        run: |\n          VERSION=\"${{ inputs.release_version }}\"\n          ARTIFACT_URL=\"https://repo1.maven.org/maven2/io/btrace/btrace-client/${VERSION}/btrace-client-${VERSION}.pom\"\n\n          echo \"Waiting for Maven Central to have: ${ARTIFACT_URL}\"\n          echo \"This requires manual release from Central Portal.\"\n          echo \"\"\n          echo \"Go to: https://central.sonatype.com/publishing/deployments\"\n          echo \"\"\n\n          MAX_ATTEMPTS=60  # 30 minutes with 30s intervals\n          ATTEMPT=0\n\n          while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do\n            ATTEMPT=$((ATTEMPT + 1))\n            echo \"Attempt ${ATTEMPT}/${MAX_ATTEMPTS}: Checking Maven Central...\"\n\n            HTTP_STATUS=$(curl -s -o /dev/null -w \"%{http_code}\" \"${ARTIFACT_URL}\")\n\n            if [ \"$HTTP_STATUS\" = \"200\" ]; then\n              echo \"\"\n              echo \"SUCCESS: Artifacts are available on Maven Central!\"\n              echo \"Proceeding with GitHub release and SDKMan announcement...\"\n              exit 0\n            fi\n\n            echo \"  Status: ${HTTP_STATUS} - Not available yet. Waiting 30s...\"\n            sleep 30\n          done\n\n          echo \"\"\n          echo \"TIMEOUT: Artifacts did not appear on Maven Central within 30 minutes.\"\n          echo \"The release was NOT finalized.\"\n          echo \"\"\n          echo \"To complete the release manually:\"\n          echo \"  1. Release artifacts via Central Portal\"\n          echo \"  2. Create GitHub release manually\"\n          echo \"  3. Run: ./gradlew :btrace-dist:sdkMinorRelease\"\n          exit 1\n\n  # ============================================================\n  # Job 5c: Update JBang catalog\n  # ============================================================\n  update-jbang-catalog:\n    name: Update JBang Catalog\n    needs: [prepare-release, wait-for-maven]\n    runs-on: ubuntu-latest\n    if: ${{ inputs.dry_run != true }}\n    steps:\n      - name: Checkout jbang-catalog\n        continue-on-error: true\n        uses: actions/checkout@v6\n        with:\n          repository: btraceio/jbang-catalog\n          token: ${{ secrets.JBANG_CATALOG_PAT || secrets.GITHUB_TOKEN }}\n          path: catalog\n\n      - name: Update catalog files\n        continue-on-error: true\n        run: |\n          VERSION=\"${{ inputs.release_version }}\"\n\n          if [ ! -d catalog ]; then\n            echo \"⚠️ Catalog checkout failed - skipping update\"\n            echo \"Add JBANG_CATALOG_PAT secret to enable automatic catalog updates\"\n            exit 0\n          fi\n\n          cd catalog\n\n          # Update btrace.java dependency\n          sed -i.bak \"s|//DEPS io.btrace:btrace-client:.*|//DEPS io.btrace:btrace-client:${VERSION}|g\" btrace.java\n\n          # Update btrace-latest.java dependency\n          sed -i.bak \"s|//DEPS io.btrace:btrace-client:.*|//DEPS io.btrace:btrace-client:${VERSION}|g\" btrace-latest.java\n\n          # Clean up backup files\n          rm -f *.bak\n\n          # Show changes\n          git diff\n\n      - name: Commit and push catalog updates\n        continue-on-error: true\n        run: |\n          VERSION=\"${{ inputs.release_version }}\"\n\n          if [ ! -d catalog ]; then\n            echo \"⚠️ Catalog checkout failed - skipping update\"\n            echo \"Add JBANG_CATALOG_PAT secret to enable automatic catalog updates\"\n            exit 0\n          fi\n\n          cd catalog\n\n          git config user.name \"github-actions[bot]\"\n          git config user.email \"github-actions[bot]@users.noreply.github.com\"\n\n          git add btrace.java btrace-latest.java\n          if git commit -m \"Update btrace to version ${VERSION}\"; then\n            git push || echo \"⚠️ Push failed - update catalog manually at https://github.com/btraceio/jbang-catalog\"\n          fi\n\n  # ============================================================\n  # Job 5d: Finalize release tag (RC -> final)\n  # ============================================================\n  finalize-tag:\n    name: Finalize Release Tag\n    needs: [prepare-release, wait-for-maven]\n    runs-on: ubuntu-latest\n    if: ${{ inputs.dry_run != true }}\n    steps:\n      - name: Checkout at release SHA\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ needs.prepare-release.outputs.release_sha }}\n          fetch-depth: 0\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Fetch tags\n        run: git fetch origin --tags\n\n      - name: Configure Git\n        run: |\n          git config user.name \"github-actions[bot]\"\n          git config user.email \"github-actions[bot]@users.noreply.github.com\"\n\n      - name: Create final tag\n        run: |\n          git tag -a \"${RELEASE_TAG}\" -m \"Release ${RELEASE_TAG}\"\n          echo \"Created final tag ${RELEASE_TAG}\"\n\n      - name: Push final tag\n        run: |\n          git push origin \"${RELEASE_TAG}\"\n          echo \"Pushed final tag ${RELEASE_TAG}\"\n\n      - name: Delete RC tag\n        run: |\n          git tag -d \"${RC_TAG}\" || true\n          git push origin \":refs/tags/${RC_TAG}\" || true\n          echo \"Deleted RC tag ${RC_TAG}\"\n\n  # ============================================================\n  # Job 6: Build distribution packages\n  # ============================================================\n  build-distributions:\n    name: Build Distributions\n    needs: prepare-release\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout release commit\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ inputs.dry_run == true && inputs.commit_sha || env.RC_TAG }}\n\n      - name: Cache Java binaries\n        id: cache-java\n        uses: actions/cache@v5\n        with:\n          path: ${{ runner.tool_cache }}/Java_*\n          key: java-${{ runner.os }}-temurin-11\n\n      - name: Set up Java\n        if: steps.cache-java.outputs.cache-hit != 'true'\n        uses: actions/setup-java@v5\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n\n      - name: Update version for dry run\n        if: ${{ inputs.dry_run == true }}\n        run: |\n          VERSION=\"${{ inputs.release_version }}\"\n          sed -i \"s/project.version = '.*'/project.version = '${VERSION}'/\" common.gradle\n\n      - name: Build distribution packages\n        run: |\n          ./gradlew :btrace-dist:build --no-daemon\n\n      - name: List artifacts\n        run: |\n          echo \"Distribution artifacts:\"\n          ls -la btrace-dist/build/distributions/\n\n      - name: Upload distribution artifacts\n        uses: actions/upload-artifact@v7\n        with:\n          name: release-distributions\n          retention-days: 7\n          path: |\n            btrace-dist/build/distributions/btrace-v${{ inputs.release_version }}-bin.tar.gz\n            btrace-dist/build/distributions/btrace-v${{ inputs.release_version }}-bin.zip\n            btrace-dist/build/distributions/btrace-v${{ inputs.release_version }}-sdkman-bin.zip\n            btrace-dist/build/distributions/*.deb\n            btrace-dist/build/distributions/*.rpm\n\n  # ============================================================\n  # Job 7: Create GitHub Release\n  # ============================================================\n  create-github-release:\n    name: Create GitHub Release\n    needs: [build-distributions, finalize-tag]\n    runs-on: ubuntu-latest\n    if: ${{ inputs.dry_run != true }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ env.RELEASE_TAG }}\n          fetch-depth: 0\n\n      - name: Download distribution artifacts\n        uses: actions/download-artifact@v8\n        with:\n          name: release-distributions\n          path: distributions\n\n      - name: Download Maven artifact\n        continue-on-error: true\n        run: |\n          VERSION=\"${{ inputs.release_version }}\"\n          BASE_URL=\"https://repo1.maven.org/maven2/io/btrace/btrace/${VERSION}\"\n          mkdir -p maven-artifacts\n          MAX_ATTEMPTS=40\n          for i in $(seq 1 $MAX_ATTEMPTS); do\n            if curl -fSL \"${BASE_URL}/btrace-${VERSION}.jar\" \\\n              -o maven-artifacts/btrace-${VERSION}.jar; then\n              echo \"Downloaded btrace-${VERSION}.jar\"\n              ls -la maven-artifacts/\n              exit 0\n            fi\n            echo \"Attempt ${i}/${MAX_ATTEMPTS} failed, retrying in 30s...\"\n            sleep 30\n          done\n          echo \"::warning::Failed to download Maven JAR after ${MAX_ATTEMPTS} attempts (~20 minutes). GitHub release will proceed without it.\"\n\n      - name: Check for no-release-notes label\n        id: check-label\n        run: |\n          # Check if this release should skip auto-generated notes\n          SKIP_NOTES=\"false\"\n          # This would check PRs merged since last release for the label\n          # For now, always generate release notes\n          echo \"skip_notes=${SKIP_NOTES}\" >> $GITHUB_OUTPUT\n\n      - name: Create GitHub Release\n        uses: softprops/action-gh-release@v2\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          tag_name: ${{ env.RELEASE_TAG }}\n          name: BTrace ${{ inputs.release_version }}\n          draft: false\n          prerelease: false\n          generate_release_notes: true\n          files: |\n            distributions/btrace-v${{ inputs.release_version }}-bin.tar.gz\n            distributions/btrace-v${{ inputs.release_version }}-bin.zip\n            distributions/btrace-v${{ inputs.release_version }}-sdkman-bin.zip\n            distributions/*.deb\n            distributions/*.rpm\n            maven-artifacts/*\n\n  # ============================================================\n  # Job 8: Update SDKMan\n  # ============================================================\n  update-sdkman:\n    name: Update SDKMan\n    needs: create-github-release\n    runs-on: ubuntu-latest\n    if: ${{ inputs.dry_run != true }}\n    steps:\n      - name: Checkout release tag\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ env.RELEASE_TAG }}\n\n      - name: Cache Java binaries\n        id: cache-java\n        uses: actions/cache@v5\n        with:\n          path: ${{ runner.tool_cache }}/Java_*\n          key: java-${{ runner.os }}-temurin-11\n\n      - name: Set up Java\n        if: steps.cache-java.outputs.cache-hit != 'true'\n        uses: actions/setup-java@v5\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n\n      - name: Announce to SDKMan\n        env:\n          SDKMAN_API_KEY: ${{ secrets.SDKMAN_KEY }}\n          SDKMAN_API_TOKEN: ${{ secrets.SDKMAN_TOKEN }}\n        run: |\n          # Use sdkMajorRelease for major releases, sdkMinorRelease otherwise\n          if [[ \"${{ inputs.release_type }}\" == \"major\" ]]; then\n            ./gradlew :btrace-dist:sdkMajorRelease --no-daemon\n          else\n            ./gradlew :btrace-dist:sdkMinorRelease --no-daemon\n          fi\n\n  # ============================================================\n  # Job 9: Update develop branch (major/minor only)\n  # ============================================================\n  update-develop:\n    name: Update Develop Branch\n    needs: prepare-release\n    runs-on: ubuntu-latest\n    if: ${{ inputs.release_type != 'patch' && inputs.dry_run != true }}\n    steps:\n      - name: Checkout develop\n        uses: actions/checkout@v6\n        with:\n          ref: develop\n          fetch-depth: 0\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Configure Git\n        run: |\n          git config user.name \"github-actions[bot]\"\n          git config user.email \"github-actions[bot]@users.noreply.github.com\"\n\n      - name: Update version in develop\n        run: |\n          NEXT_VERSION=\"${{ inputs.next_snapshot }}\"\n          sed -i \"s/project.version = '.*'/project.version = '${NEXT_VERSION}'/\" common.gradle\n          echo \"Updated develop to ${NEXT_VERSION}\"\n          grep \"project.version\" common.gradle\n\n      - name: Commit and push\n        run: |\n          git add common.gradle\n          git commit -m \"Bump version to ${{ inputs.next_snapshot }} after ${RELEASE_TAG} release\"\n          git push origin develop\n\n  # ============================================================\n  # Job 10: Update release branch to next patch snapshot\n  # ============================================================\n  update-release-branch:\n    name: Update Release Branch\n    needs: [prepare-release, create-github-release]\n    runs-on: ubuntu-latest\n    if: ${{ inputs.dry_run != true }}\n    steps:\n      - name: Checkout release branch\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ inputs.release_branch }}\n          fetch-depth: 0\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Configure Git\n        run: |\n          git config user.name \"github-actions[bot]\"\n          git config user.email \"github-actions[bot]@users.noreply.github.com\"\n\n      - name: Calculate next patch snapshot\n        id: next-version\n        run: |\n          CURRENT=\"${{ inputs.release_version }}\"\n          MAJOR=$(echo $CURRENT | cut -d. -f1)\n          MINOR=$(echo $CURRENT | cut -d. -f2)\n          PATCH=$(echo $CURRENT | cut -d. -f3)\n          NEXT_PATCH=$((PATCH + 1))\n          NEXT_VERSION=\"${MAJOR}.${MINOR}.${NEXT_PATCH}-SNAPSHOT\"\n          echo \"version=${NEXT_VERSION}\" >> $GITHUB_OUTPUT\n          echo \"Next patch version: ${NEXT_VERSION}\"\n\n      - name: Update version in release branch\n        run: |\n          NEXT_VERSION=\"${{ steps.next-version.outputs.version }}\"\n          sed -i \"s/project.version = '.*'/project.version = '${NEXT_VERSION}'/\" common.gradle\n          echo \"Updated release branch to ${NEXT_VERSION}\"\n          grep \"project.version\" common.gradle\n\n      - name: Commit and push\n        run: |\n          git add common.gradle\n          git commit -m \"Bump version to ${{ steps.next-version.outputs.version }} for next patch release\"\n          git push origin ${{ inputs.release_branch }}\n\n  # ============================================================\n  # Job 11: Manage milestones\n  # ============================================================\n  update-milestones:\n    name: Update Milestones\n    needs: create-github-release\n    runs-on: ubuntu-latest\n    if: ${{ inputs.dry_run != true }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n\n      - name: Create and close milestone\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          MILESTONE_TITLE=\"${{ inputs.release_version }}\"\n\n          # Check if milestone exists\n          MILESTONE=$(gh api repos/${{ github.repository }}/milestones --jq \".[] | select(.title == \\\"${MILESTONE_TITLE}\\\")\")\n\n          if [[ -z \"${MILESTONE}\" ]]; then\n            echo \"Creating milestone ${MILESTONE_TITLE}...\"\n            gh api repos/${{ github.repository }}/milestones \\\n              -X POST \\\n              -f title=\"${MILESTONE_TITLE}\" \\\n              -f state=\"closed\" \\\n              -f description=\"Released as ${RELEASE_TAG}\"\n          else\n            MILESTONE_NUMBER=$(echo \"${MILESTONE}\" | jq -r '.number')\n            echo \"Closing existing milestone ${MILESTONE_TITLE} (#${MILESTONE_NUMBER})...\"\n            gh api repos/${{ github.repository }}/milestones/${MILESTONE_NUMBER} \\\n              -X PATCH \\\n              -f state=\"closed\"\n          fi\n\n      - name: Associate merged PRs with milestone\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          # Get the milestone number\n          MILESTONE_TITLE=\"${{ inputs.release_version }}\"\n          MILESTONE_NUMBER=$(gh api repos/${{ github.repository }}/milestones --jq \".[] | select(.title == \\\"${MILESTONE_TITLE}\\\") | .number\")\n\n          if [[ -z \"${MILESTONE_NUMBER}\" ]]; then\n            echo \"Warning: Could not find milestone ${MILESTONE_TITLE}\"\n            exit 0\n          fi\n\n          # Find the previous release tag\n          PREV_TAG=$(git describe --tags --abbrev=0 \"${RELEASE_TAG}^\" 2>/dev/null || echo \"\")\n\n          if [[ -z \"${PREV_TAG}\" ]]; then\n            echo \"No previous tag found, skipping PR association\"\n            exit 0\n          fi\n\n          echo \"Finding PRs merged between ${PREV_TAG} and ${RELEASE_TAG}...\"\n\n          # Get commits between tags\n          COMMITS=$(git log \"${PREV_TAG}..${RELEASE_TAG}\" --pretty=format:\"%H\" 2>/dev/null || echo \"\")\n\n          for COMMIT in ${COMMITS}; do\n            # Find PR associated with this commit\n            PR_NUMBER=$(gh api repos/${{ github.repository }}/commits/${COMMIT}/pulls --jq '.[0].number' 2>/dev/null || echo \"\")\n\n            if [[ -n \"${PR_NUMBER}\" && \"${PR_NUMBER}\" != \"null\" ]]; then\n              echo \"Associating PR #${PR_NUMBER} with milestone ${MILESTONE_TITLE}...\"\n              gh api repos/${{ github.repository }}/issues/${PR_NUMBER} \\\n                -X PATCH \\\n                -f milestone=\"${MILESTONE_NUMBER}\" 2>/dev/null || true\n            fi\n          done\n\n  # ============================================================\n  # Job 12: Release summary\n  # ============================================================\n  summary:\n    name: Release Summary\n    needs: [create-github-release, update-sdkman, update-milestones, update-jbang-catalog, finalize-tag]\n    runs-on: ubuntu-latest\n    if: always()\n    steps:\n      - name: Generate summary\n        run: |\n          echo \"# Release Summary\" >> $GITHUB_STEP_SUMMARY\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n          echo \"## Release Details\" >> $GITHUB_STEP_SUMMARY\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Property | Value |\" >> $GITHUB_STEP_SUMMARY\n          echo \"|----------|-------|\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Version | ${{ inputs.release_version }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Tag | ${RELEASE_TAG} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Release Type | ${{ inputs.release_type }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Source Commit | ${{ inputs.commit_sha }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Release Branch | ${{ inputs.release_branch }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Dry Run | ${{ inputs.dry_run }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n\n          if [[ \"${{ inputs.dry_run }}\" != \"true\" ]]; then\n            echo \"## Links\" >> $GITHUB_STEP_SUMMARY\n            echo \"\" >> $GITHUB_STEP_SUMMARY\n            echo \"- [GitHub Release](https://github.com/${{ github.repository }}/releases/tag/${RELEASE_TAG})\" >> $GITHUB_STEP_SUMMARY\n            echo \"- [Maven Central](https://central.sonatype.com/search?q=io.btrace&version=${{ inputs.release_version }})\" >> $GITHUB_STEP_SUMMARY\n            echo \"- [SDKMan](https://sdkman.io/sdks#btrace)\" >> $GITHUB_STEP_SUMMARY\n            echo \"- JBang: \\`jbang btrace@${{ inputs.release_version }}\\` (uses Maven Central)\" >> $GITHUB_STEP_SUMMARY\n            echo \"\" >> $GITHUB_STEP_SUMMARY\n            echo \"## Maven Coordinates\" >> $GITHUB_STEP_SUMMARY\n            echo \"\" >> $GITHUB_STEP_SUMMARY\n            echo '```xml' >> $GITHUB_STEP_SUMMARY\n            echo '<dependency>' >> $GITHUB_STEP_SUMMARY\n            echo '    <groupId>io.btrace</groupId>' >> $GITHUB_STEP_SUMMARY\n            echo '    <artifactId>btrace-client</artifactId>' >> $GITHUB_STEP_SUMMARY\n            echo \"    <version>${{ inputs.release_version }}</version>\" >> $GITHUB_STEP_SUMMARY\n            echo '</dependency>' >> $GITHUB_STEP_SUMMARY\n            echo '```' >> $GITHUB_STEP_SUMMARY\n          else\n            echo \"## Dry Run Mode\" >> $GITHUB_STEP_SUMMARY\n            echo \"\" >> $GITHUB_STEP_SUMMARY\n            echo \"> **Note:** This was a dry run. No artifacts were published or tags created.\" >> $GITHUB_STEP_SUMMARY\n          fi\n\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n          echo \"## Job Status\" >> $GITHUB_STEP_SUMMARY\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Job | Status |\" >> $GITHUB_STEP_SUMMARY\n          echo \"|-----|--------|\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Validate | ${{ needs.validate.result || 'skipped' }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Build & Test | ${{ needs.build-and-test.result || 'skipped' }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Integration Tests | ${{ needs.integration-tests.result || 'skipped' }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Prepare Release | ${{ needs.prepare-release.result || 'skipped' }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Stage Maven | ${{ needs.stage-maven.result || 'skipped' }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Wait for Maven | ${{ needs.wait-for-maven.result || 'skipped' }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Finalize Tag | ${{ needs.finalize-tag.result || 'skipped' }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| GitHub Release | ${{ needs.create-github-release.result || 'skipped' }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| SDKMan | ${{ needs.update-sdkman.result || 'skipped' }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| JBang Catalog | ${{ needs.update-jbang-catalog.result || 'skipped' }} |\" >> $GITHUB_STEP_SUMMARY\n          echo \"| Milestones | ${{ needs.update-milestones.result || 'skipped' }} |\" >> $GITHUB_STEP_SUMMARY\n\n  # ============================================================\n  # Job 13: Cleanup\n  # ============================================================\n  cleanup:\n    name: Cleanup Artifacts\n    needs: [summary]\n    runs-on: ubuntu-latest\n    if: always()\n    steps:\n      - name: Cleanup temporary artifacts\n        uses: geekyeggo/delete-artifact@v6\n        with:\n          name: |\n            dist-build\n            test-trace\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: Mark stale issues and pull requests\n\non:\n  schedule:\n  - cron: \"0 0 * * *\"\n\njobs:\n  stale:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/stale@v10\n      with:\n        repo-token: ${{ secrets.GITHUB_TOKEN }}\n        stale-issue-message: 'Stale issue message'\n        stale-pr-message: 'Stale pull request message'\n        stale-issue-label: 'no-issue-activity'\n        stale-pr-label: 'no-pr-activity'\n"
  },
  {
    "path": ".github/workflows/update-jdk-versions.yml",
    "content": "name: Update JDK Test Versions\n\non:\n  schedule:\n    - cron: '0 6 * * 1'\n  workflow_dispatch:\n\npermissions:\n  contents: write\n  pull-requests: write\n\njobs:\n  update-versions:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: develop\n          token: ${{ secrets.PAT_WORKFLOW }}\n\n      - name: Check for version updates\n        id: update\n        run: |\n          chmod +x scripts/update-jdk-versions.sh\n          if changes=$(scripts/update-jdk-versions.sh); then\n            echo \"changed=true\" >> \"$GITHUB_OUTPUT\"\n            {\n              echo \"body<<EOF\"\n              echo \"$changes\"\n              echo \"EOF\"\n            } >> \"$GITHUB_OUTPUT\"\n          else\n            echo \"changed=false\" >> \"$GITHUB_OUTPUT\"\n          fi\n\n      - name: Create Pull Request\n        if: steps.update.outputs.changed == 'true'\n        uses: peter-evans/create-pull-request@v8\n        with:\n          token: ${{ secrets.PAT_WORKFLOW }}\n          branch: automation/update-jdk-versions\n          base: develop\n          title: 'chore: update JDK test versions'\n          draft: true\n          labels: automation\n          commit-message: 'chore: update JDK test versions'\n          body: |\n            Automated JDK version update detected by SDKMan API.\n\n            ### Changes\n            ${{ steps.update.outputs.body }}\n"
  },
  {
    "path": ".github/workflows/v2-protocol-tests.yml",
    "content": "# Workflow for testing BTrace Binary Protocol v2\n# This workflow runs comprehensive tests for the v2 protocol implementation\n# including unit tests, JMH benchmarks, and protocol negotiation tests\n\nname: V2 Protocol Tests\n\non:\n  # Run on PRs when labeled with 'test:v2-protocol'\n  pull_request:\n    types: [ labeled ]\n  # Run weekly on Sunday at 2 AM UTC\n  schedule:\n    - cron: '0 2 * * 0'\n  # Allow manual trigger\n  workflow_dispatch:\n\ndefaults:\n  run:\n    shell: bash\n\njobs:\n  unit-tests:\n    name: V2 Protocol Unit Tests\n    runs-on: ubuntu-latest\n    # Only run if triggered by schedule, manual dispatch, or PR with 'test:v2-protocol' label\n    if: |\n      github.event_name == 'schedule' ||\n      github.event_name == 'workflow_dispatch' ||\n      (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'test:v2-protocol'))\n    strategy:\n      matrix:\n        java: [ 11, 17, 21 ]\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Cache Java binaries\n        id: cache-java\n        uses: actions/cache@v5\n        with:\n          path: ${{ runner.tool_cache }}/Java_*\n          key: java-${{ runner.os }}-temurin-${{ matrix.java }}\n\n      - name: Set up JDK ${{ matrix.java }}\n        if: steps.cache-java.outputs.cache-hit != 'true'\n        uses: actions/setup-java@v5\n        with:\n          java-version: ${{ matrix.java }}\n          distribution: temurin\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n\n      - name: Cache Gradle packages\n        uses: actions/cache@v5\n        with:\n          path: |\n            ~/.gradle/caches\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}\n          restore-keys: |\n            ${{ runner.os }}-gradle-\n\n      - name: Run V2 Protocol Tests\n        run: |\n          ./gradlew :btrace-core:test --tests \"org.openjdk.btrace.core.comm.v2.*\" \\\n                                       --tests \"org.openjdk.btrace.core.comm.Protocol*\" \\\n                                       --tests \"org.openjdk.btrace.core.comm.WireProtocol*\" \\\n                                       --rerun-tasks\n\n      - name: Upload Test Reports\n        if: always()\n        uses: actions/upload-artifact@v7\n        with:\n          name: test-reports-java-${{ matrix.java }}\n          retention-days: 7\n          path: |\n            btrace-core/build/reports/tests/**\n            btrace-core/build/test-results/**\n\n  protocol-negotiation-tests:\n    name: Protocol Negotiation Tests\n    runs-on: ubuntu-latest\n    if: |\n      github.event_name == 'schedule' ||\n      github.event_name == 'workflow_dispatch' ||\n      (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'test:v2-protocol'))\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Cache Java binaries\n        id: cache-java\n        uses: actions/cache@v5\n        with:\n          path: ${{ runner.tool_cache }}/Java_*\n          key: java-${{ runner.os }}-temurin-11\n\n      - name: Set up JDK 11\n        if: steps.cache-java.outputs.cache-hit != 'true'\n        uses: actions/setup-java@v5\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n\n      - name: Run Protocol Negotiation Tests\n        run: |\n          ./gradlew :btrace-core:test --tests \"org.openjdk.btrace.core.comm.ProtocolNegotiatorTest\" \\\n                                       --tests \"org.openjdk.btrace.core.comm.ProtocolConfigTest\" \\\n                                       --tests \"org.openjdk.btrace.core.comm.WireProtocolTest\" \\\n                                       --rerun-tasks\n\n      - name: Verify Protocol Version Detection\n        run: |\n          echo \"Testing V1 protocol detection...\"\n          ./gradlew :btrace-core:test --tests \"*ProtocolNegotiatorTest.testNegotiateV1*\"\n          echo \"Testing V2 protocol detection...\"\n          ./gradlew :btrace-core:test --tests \"*ProtocolNegotiatorTest.testNegotiateV2*\"\n\n      - name: Upload Negotiation Test Reports\n        if: always()\n        uses: actions/upload-artifact@v7\n        with:\n          name: negotiation-test-reports\n          retention-days: 7\n          path: |\n            btrace-core/build/reports/tests/**\n            btrace-core/build/test-results/**\n\n  edge-case-tests:\n    name: Edge Case and Boundary Tests\n    runs-on: ubuntu-latest\n    if: |\n      github.event_name == 'schedule' ||\n      github.event_name == 'workflow_dispatch' ||\n      (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'test:v2-protocol'))\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Cache Java binaries\n        id: cache-java\n        uses: actions/cache@v5\n        with:\n          path: ${{ runner.tool_cache }}/Java_*\n          key: java-${{ runner.os }}-temurin-11\n\n      - name: Set up JDK 11\n        if: steps.cache-java.outputs.cache-hit != 'true'\n        uses: actions/setup-java@v5\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n\n      - name: Run Edge Case Tests\n        run: |\n          ./gradlew :btrace-core:test --tests \"org.openjdk.btrace.core.comm.v2.BinaryProtocolEdgeCasesTest\" \\\n                                       --rerun-tasks\n\n      - name: Test Large Messages\n        run: |\n          ./gradlew :btrace-core:test --tests \"*testVeryLargeMessage\" \\\n                                       --tests \"*testLargeBytecodeArray\" \\\n                                       --tests \"*testMapWith1000Entries\"\n\n      - name: Test Compression\n        run: |\n          ./gradlew :btrace-core:test --tests \"*testCompressionThreshold\" \\\n                                       --tests \"*testHighlyCompressibleMessage\" \\\n                                       --tests \"*testCompressionJustAboveThreshold\"\n\n      - name: Upload Edge Case Reports\n        if: always()\n        uses: actions/upload-artifact@v7\n        with:\n          name: edge-case-reports\n          retention-days: 7\n          path: |\n            btrace-core/build/reports/tests/**\n\n  jmh-benchmarks:\n    name: JMH Performance Benchmarks\n    runs-on: ubuntu-latest\n    if: github.event_name == 'workflow_dispatch' || contains(github.event.head_commit.message, '[benchmark]')\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Cache Java binaries\n        id: cache-java\n        uses: actions/cache@v5\n        with:\n          path: ${{ runner.tool_cache }}/Java_*\n          key: java-${{ runner.os }}-temurin-11\n\n      - name: Set up JDK 11\n        if: steps.cache-java.outputs.cache-hit != 'true'\n        uses: actions/setup-java@v5\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n\n      - name: Run Quick JMH Benchmarks (warmup=1, iterations=2, fork=1)\n        run: |\n          ./gradlew :btrace-core:jmh \\\n            -PjmhInclude=\".*Serialize.*\" \\\n            -Pjmh.warmupIterations=1 \\\n            -Pjmh.iterations=2 \\\n            -Pjmh.fork=1\n\n      - name: Upload JMH Results\n        if: always()\n        uses: actions/upload-artifact@v7\n        with:\n          name: jmh-results\n          retention-days: 30\n          path: |\n            btrace-core/build/reports/jmh/**\n            btrace-core/build/jmh-results/**\n\n  protocol-compatibility:\n    name: Protocol Compatibility Matrix\n    runs-on: ubuntu-latest\n    if: |\n      github.event_name == 'schedule' ||\n      github.event_name == 'workflow_dispatch' ||\n      (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'test:v2-protocol'))\n    strategy:\n      matrix:\n        scenario:\n          - name: \"V2-to-V2\"\n            client: \"v2\"\n            agent: \"v2\"\n          - name: \"V1-to-V1\"\n            client: \"v1\"\n            agent: \"v1\"\n          - name: \"V2-to-V1\"\n            client: \"v2\"\n            agent: \"v1\"\n          - name: \"V1-to-V2\"\n            client: \"v1\"\n            agent: \"v2\"\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Cache Java binaries\n        id: cache-java\n        uses: actions/cache@v5\n        with:\n          path: ${{ runner.tool_cache }}/Java_*\n          key: java-${{ runner.os }}-temurin-11\n\n      - name: Set up JDK 11\n        if: steps.cache-java.outputs.cache-hit != 'true'\n        uses: actions/setup-java@v5\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n\n      - name: Test ${{ matrix.scenario.name }} Compatibility\n        run: |\n          echo \"Testing compatibility: Client=${{ matrix.scenario.client }} Agent=${{ matrix.scenario.agent }}\"\n          ./gradlew :btrace-core:test --tests \"org.openjdk.btrace.core.comm.WireProtocolTest\" \\\n                                       --rerun-tasks \\\n            -Dbtrace.comm.protocol=${{ matrix.scenario.client }}\n\n      - name: Upload Compatibility Reports\n        if: always()\n        uses: actions/upload-artifact@v7\n        with:\n          name: compatibility-${{ matrix.scenario.name }}\n          retention-days: 7\n          path: |\n            btrace-core/build/reports/tests/**\n\n  test-summary:\n    name: Test Summary\n    runs-on: ubuntu-latest\n    needs: [unit-tests, protocol-negotiation-tests, edge-case-tests, protocol-compatibility]\n    if: always()\n    steps:\n      - name: Download All Test Reports\n        uses: actions/download-artifact@v8\n        with:\n          path: test-reports\n\n      - name: Generate Test Summary\n        run: |\n          echo \"# V2 Protocol Test Summary\" >> $GITHUB_STEP_SUMMARY\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n          echo \"## Test Results\" >> $GITHUB_STEP_SUMMARY\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n\n          # Count test results\n          total_tests=0\n          passed_tests=0\n          failed_tests=0\n\n          for report in test-reports/*/test-results/test/*.xml; do\n            if [ -f \"$report\" ]; then\n              tests=$(grep -oP 'tests=\"\\K[0-9]+' \"$report\" || echo \"0\")\n              failures=$(grep -oP 'failures=\"\\K[0-9]+' \"$report\" || echo \"0\")\n              total_tests=$((total_tests + tests))\n              failed_tests=$((failed_tests + failures))\n            fi\n          done\n\n          passed_tests=$((total_tests - failed_tests))\n\n          echo \"- **Total Tests:** $total_tests\" >> $GITHUB_STEP_SUMMARY\n          echo \"- **Passed:** ✅ $passed_tests\" >> $GITHUB_STEP_SUMMARY\n          echo \"- **Failed:** ❌ $failed_tests\" >> $GITHUB_STEP_SUMMARY\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n\n          if [ $failed_tests -eq 0 ]; then\n            echo \"✅ All V2 protocol tests passed!\" >> $GITHUB_STEP_SUMMARY\n            exit 0\n          else\n            echo \"❌ Some tests failed. Please review the reports.\" >> $GITHUB_STEP_SUMMARY\n            exit 1\n          fi\n\n  code-coverage:\n    name: Code Coverage\n    runs-on: ubuntu-latest\n    if: |\n      github.event_name == 'schedule' ||\n      github.event_name == 'workflow_dispatch' ||\n      (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'test:v2-protocol'))\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Cache Java binaries\n        id: cache-java\n        uses: actions/cache@v5\n        with:\n          path: ${{ runner.tool_cache }}/Java_*\n          key: java-${{ runner.os }}-temurin-11\n\n      - name: Set up JDK 11\n        if: steps.cache-java.outputs.cache-hit != 'true'\n        uses: actions/setup-java@v5\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v6\n\n      - name: Run Tests with Coverage\n        run: |\n          ./gradlew :btrace-core:test jacocoTestReport\n\n      - name: Upload Coverage Reports\n        uses: actions/upload-artifact@v7\n        with:\n          name: coverage-reports\n          retention-days: 30\n          path: |\n            btrace-core/build/reports/jacoco/**\n            btrace-core/build/jacoco/**\n\n      - name: Generate Coverage Summary\n        run: |\n          if [ -f \"btrace-core/build/reports/jacoco/test/html/index.html\" ]; then\n            echo \"## Code Coverage\" >> $GITHUB_STEP_SUMMARY\n            echo \"Coverage report generated successfully\" >> $GITHUB_STEP_SUMMARY\n            echo \"See artifacts for detailed coverage data\" >> $GITHUB_STEP_SUMMARY\n          fi\n"
  },
  {
    "path": ".gitignore",
    "content": "*.class\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.ear\n\n# Un-ignore specific files\n!btrace-instr/src/test/resources/packed/test-pack.jar\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n\nbuild\ndist\nmake/netbeans/nbproject/private\nTEST-*\nmake/junit*\nmake/private.properties\nbtrace-benchmark/target\nbtrace-benchmark/build\nbenchmark/*.iml\njunit*\n/btrace-statsd/target/\n*.iml\n.gradle\n.gradle-user\n.idea\n!/lib/btrace-asm-*.jar\n!/lib/btrace-jctools-core-*.jar\n!/lib/btrace-hppcrt-*.jar\n!/test-lib/*.jar\nCHANGELOG.md\ngradle.properties\n/.nb-gradle/\n/.nb-gradle-properties\n.github_changelog_generator\n**/out/*\ngradle-wrapper.properties\n\n/.java.versions\n"
  },
  {
    "path": ".muse/advisor.md",
    "content": "# BTrace Project Advisor\n\n## Repository: btraceio/btrace\n\n### Branch model\n\n- **`develop`** is the sole integration branch — ALL pull requests must target `develop`, never `master`.\n- `master` does not exist on the remote.\n- Release tags are cut from `develop` after a stabilization window.\n\n### Build commands\n\n```bash\n# Full build with dist packages\n./gradlew :btrace-dist:build\n\n# Module-specific build (faster)\n./gradlew :<module>:build -x test\n\n# All tests\n./gradlew test\n\n# Instrumentation tests only (fastest for instr changes)\n./gradlew :btrace-instr:test\n\n# Regenerate golden files after intentional bytecode changes\n./gradlew :btrace-instr:test -PupdateTestData\n\n# Integration tests (requires Docker + full dist build first)\n./gradlew :btrace-dist:build\n./gradlew :integration-tests:test -Pintegration\n\n# Format check / auto-format (Google Java Format via Spotless)\n./gradlew spotlessCheck\n./gradlew spotlessApply\n```\n\n### Module layout\n\n| Module | Purpose |\n|---|---|\n| `btrace-core` | Annotations, wire protocol, shared types — must stay Java 8 compatible |\n| `btrace-compiler` | Script compilation + safety verification (`Verifier.java`) |\n| `btrace-instr` | ASM-based bytecode instrumentation; probe factory; `HandlerRepositoryImpl` |\n| `btrace-runtime` | Multi-version runtime impls (base/java9/java11/java15); `IndyDispatcher` |\n| `btrace-agent` | Java agent entry point; `RemoteClient`, `FileClient` |\n| `btrace-client` | CLI client tool |\n| `btrace-dist` | Distribution packaging |\n| `integration-tests` | End-to-end Docker-based tests |\n| `benchmarks` | JMH benchmarks |\n\n### Key architectural constraints\n\n- `btrace-core` and `btrace-runtime` (src/main/java/) must compile at Java 8 source/target level.\n- Multi-version runtime jars: `src/main/java9/`, `src/main/java11/`, `src/main/java15/` — each compiled at its respective release level.\n- `btrace-boot.jar` is on the bootstrap classpath; classes in `btrace-runtime` that are referenced from INVOKEDYNAMIC bootstrap methods must be bootstrap-loadable.\n- All probe script classes are defined in the bootstrap CL (via `Unsafe.defineClass` with `mustBeBootstrap=true` when `isTransforming()`).\n- BTrace verifier enforces that probe handler methods are `public static void` — `publicLookup().findStatic()` is therefore sufficient.\n- Golden files for instrumentation tests live in `btrace-instr/src/test/resources/instrumentorTestData/dynamic/`. Run with `-PupdateTestData` to regenerate after intentional bytecode changes.\n\n### PR checklist\n\nBefore opening a PR, verify:\n1. Branch targets **`develop`** (never `master`)\n2. `./gradlew spotlessApply` applied\n3. `./gradlew :btrace-instr:test` passes\n4. Golden files regenerated if instrumented bytecode changed (`-PupdateTestData`)\n5. If touching runtime multi-version code: test on JDK 11 and JDK 17+\n"
  },
  {
    "path": "AGENTS.md",
    "content": "# Repository Guidelines\n\n## Project Structure & Modules\n- Root uses Gradle with multiple modules named `btrace-*`.\n- Core code lives in module directories (for example, `btrace-core`, `btrace-agent`, `btrace-runtime`, `btrace-client`, `btrace-instr`).\n- Distributions are built from `btrace-dist`.\n- Integration tests live in `integration-tests`; benchmarks in `benchmarks/*`; docs in `docs/`.\n\n## Architecture Overview\n- btrace-agent: Attachable Java agent that installs a class transformer and manages script lifecycle (load/unload), output routing, and optional JFR hooks.\n- btrace-compiler: Verifies and compiles BTrace scripts to bytecode.\n- btrace-instr: ASM-based instrumentation and weaving utilities used by the agent/compiler.\n- btrace-runtime: APIs exposed to scripts; provides safe helpers for printing, timers, and data collection.\n- btrace-client: CLI/attach tooling that sends compiled scripts to the target JVM and streams results.\n- extensions: API + implementations packaged as BTrace extensions (for example, statsd and metrics under `btrace-extensions/*`).\n- Flow: client attaches → compiles/sends script → agent loads and instruments target classes → runtime emits events → client displays/exports.\n\n### High-Level Flow\n```\n +--------------+     attach/send     +-------------+     transform     +------------------+\n | btrace-client|  -----------------> | btrace-agent|  --------------> | instrumented JVM |\n +--------------+                      +-------------+                   +------------------+\n        ^                                       |  ^                               |\n        |     events/logs/stdout                |  | load/unload scripts            |\n        |  <------------------------------------+  +-------------------------------+\n        |                                                                           \n        +--------- optional exporters via services (eg. statsd) -------------------->\n```\n\n### Modules (at a glance)\n```\n btrace-client  ->  btrace-agent  ->  btrace-instr\n                         |                 |\n                         v                 v\n                   btrace-runtime     extensions (e.g., statsd, utils, metrics)\n\n btrace-compiler  (validates/compiles scripts)\n btrace-dist      (packages binaries)\n```\n\n## Distribution Architecture: Masked JAR\n\nBTrace uses a **single masked JAR** (`btrace.jar`) as its distribution artifact. This JAR contains:\n\n### Structure\n```\nbtrace.jar\n├── META-INF/\n│   ├── MANIFEST.MF (Main-Class, Premain-Class, Agent-Class → org.openjdk.btrace.boot.Loader)\n│   ├── btrace/\n│   │   ├── agent/*.classdata    (agent classes - loaded in agent mode)\n│   │   ├── client/*.classdata   (client classes - loaded in client mode)\n│   │   └── shared/*.classdata   (shared classes - loaded in both modes)\n├── org/openjdk/btrace/boot/     (bootstrap classes - visible to JVM)\n└── org/openjdk/btrace/core/     (core/runtime classes from bootstrap module)\n```\n\n### Class Loading Strategy\n\n1. **Bootstrap Classes** (`.class` files in root):\n   - Loaded by bootstrap classloader\n   - Visible to JVM and all code\n   - Includes: Loader, MaskedClassLoader, MaskedJarUtils\n   - These classes initialize the masked jar system\n\n2. **Agent Classes** (`.classdata` in `META-INF/btrace/agent/`):\n   - Loaded via MaskedClassLoader in agent mode\n   - Isolated from application classes\n   - Includes: btrace-agent, btrace-instr, btrace-runtime, relocated jctools\n\n3. **Client Classes** (`.classdata` in `META-INF/btrace/client/`):\n   - Loaded via MaskedClassLoader in client mode\n   - Includes: btrace-client, btrace-compiler, lanterna UI\n\n4. **Shared Classes** (`.classdata` in `META-INF/btrace/shared/`):\n   - Loaded in both agent and client modes\n   - Includes: communication protocol, annotations, ASM core\n   - Critical for agent-client communication\n\n### Why Masked JAR?\n\n- **Single Source of Truth**: One JAR for all use cases (agent, client, standalone)\n- **Bootstrap Isolation**: Agent/client classes hidden from JVM, preventing conflicts\n- **No Embedded JARs**: Eliminates nested JAR extraction overhead\n- **Simplified Build**: Removed redundant uber jar - masked jar handles everything\n\n### Build Process\n\nThe masked JAR is built in `btrace-dist/build.gradle`:\n1. `allClassesShadow` - Creates intermediate shadow jar with all dependencies and relocations\n2. `prepareAgentClassdata` - Extracts agent classes, renames `.class` → `.classdata`\n3. `prepareClientClassdata` - Extracts client classes, renames `.class` → `.classdata`\n4. `prepareSharedClassdata` - Extracts shared classes, renames `.class` → `.classdata`\n5. `btraceJar` - Combines bootstrap classes (as `.class`) + masked classes (as `.classdata`)\n\n### Debugging Tips\n\n- **ClassNotFoundException in agent mode**: Check if class is in `META-INF/btrace/agent/` (or shared if needed)\n- **ClassNotFoundException in client mode**: Check if class is in `META-INF/btrace/client/` (or shared if needed)\n- **NoClassDefFoundError between modes**: Class may need to be in shared section\n- **Inspect masked JAR**: `unzip -l btrace.jar | grep -E \"(\\.class|\\.classdata)\"`\n- **Check manifest**: `unzip -p btrace.jar META-INF/MANIFEST.MF`\n\n## Launch Modes\n```\nLaunch-time (agent mode):\n  java -javaagent:$BTRACE_HOME/libs/btrace.jar=script=MyTrace.java -jar app.jar\n           |-> Loader.premain() -> loads agent classes from .classdata -> installs transformer\n\nAttach-time (client mode):\n  btrace <PID> MyTrace.java\n           |-> Loader as Main-Class -> loads client classes from .classdata -> attaches to target JVM\n           |-> Target JVM: Loader.agentmain() -> loads agent classes from .classdata -> instruments\n\nStandalone (client mode):\n  java -jar btrace.jar <args>\n           |-> Same as attach-time, Loader delegates to client\n```\n\n## Troubleshooting\n- Attach disabled: if JVM was started with `-XX:+DisableAttachMechanism`, remove it or relaunch without it.\n- Permission errors: attach requires same OS user as target JVM; on Linux/macOS avoid sudo mixing; check container/JDK permissions.\n- Toolchains: ensure `JAVA_HOME` and optional `TEST_JAVA_HOME` point to valid JDKs; for integration tests, build `btrace-dist` first so client/libs exist.\n\n### Masked JAR Troubleshooting\n- **ClassNotFoundException with .classdata**: MaskedClassLoader can't find class in masked sections. Check:\n  1. Is the class in the correct section? (agent/client/shared)\n  2. Was the class relocated? Check package name matches relocated path\n  3. Did the build complete successfully? Rebuild with `./gradlew clean :btrace-dist:btraceJar`\n- **Shared classes**: If a class is used by BOTH agent and client (e.g., comm protocol, annotations), it MUST be in the shared section\n- **Bootstrap vs Masked**: Bootstrap classes (.class) are visible everywhere; masked classes (.classdata) are isolated per-mode\n- **Build order matters**: `allClassesShadow` must complete before prepare*Classdata tasks run\n\n## Example Script\n```java\npackage helloworld;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.types.AnyType;\n\n@BTrace\npublic class MyTrace {\n  @OnMethod(clazz=\"extra.HelloWorld\", method=\"/.*/\")\n  public static void onAny(@ProbeMethodName String pmn) {\n    println(\"entered: \" + pmn);\n  }\n}\n```\nRun with: `btrace <PID> MyTrace.java` (see docs/BTraceTutorial.md for steps).\n\n```java\n// Args capture\npackage helloworld;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.types.AnyType;\n\n@BTrace\npublic class ArgsTrace {\n  @OnMethod(clazz=\"extra.HelloWorld\", method=\"/call.*/\")\n  public static void onCall(@ProbeMethodName String pmn, AnyType[] args) {\n    println(\"args for \" + pmn);\n    printArray(args);\n  }\n}\n```\n\n```java\n// Return value and duration\npackage helloworld;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.types.AnyType;\n\n@BTrace\npublic class ReturnTrace {\n  @OnMethod(clazz=\"extra.HelloWorld\", method=\"callC\", location=@Location(Kind.RETURN))\n  public static void onReturn(@Duration long dur, @Return AnyType ret) {\n    println(\"callC ret=\" + str(ret) + \", dur(ns)=\" + dur);\n  }\n}\n```\n\n## Build, Test, and Development\n! Do not consume the gradle task logs directly. !\n! Write the output to a file, running through grep to include only relevant information and then read the log file. !\n\n- Full build: `./gradlew build` — compiles all modules and runs unit tests.\n- Distribution: `./gradlew :btrace-dist:build` — creates ZIP/TGZ/RPM/DEB and an exploded layout under `btrace-dist/build/resources/main`.\n- Unit tests: `./gradlew test` — JUnit 5, runs per-module tests.\n- Integration tests: first build dist, then `./gradlew -Pintegration test`.\n  - Requires `JAVA_HOME` and typically `TEST_JAVA_HOME` (e.g., JDK 11). Example: `TEST_JAVA_HOME=$JAVA_11_HOME ./gradlew -Pintegration test`.\n- Formatting: `./gradlew spotlessApply` (check with `spotlessCheck`).\n- Coverage: `./gradlew jacocoTestReport` (CI publishes to Codecov).\n\n## Coding Style & Naming\n- Language: Java. Source/target set to 8; toolchains compile with JDK 11.\n- Format: Google Java Format via Spotless. Import order enforced; unused imports removed.\n- Packages under `org.openjdk.btrace.*`.\n- Module names follow `btrace-<component>` (e.g., `btrace-extensions:btrace-utils`).\n\n## Testing Guidelines\n- Framework: JUnit Jupiter (JUnit 5).\n- Unit tests reside under `src/test/java`; name classes with `*Test`.\n- Integration tests in `integration-tests/src/test/java`; BTrace scripts under `integration-tests/src/test/btrace`.\n- For integration runs, ensure `btrace-dist/build/resources/main/v<version>/libs/btrace.jar` exists (created by the dist build).\n- The masked JAR is used for all integration tests - both agent and client modes use the same artifact.\n\n## Commit & Pull Request Guidelines\n- Commit style: Conventional Commits (e.g., `feat(core): add probe`, `fix(instr): handle null arg`).\n- PRs must be from signers of the Oracle Contributor Agreement (OCA) — see README.\n- PR checklist:\n  - Clear description and rationale; link related issues.\n  - Tests updated/added; CI green across unit and integration suites.\n  - Formatting passes (`spotlessCheck`); no unrelated changes.\n  - For behavior changes, include before/after notes or relevant logs.\n\n## Tips & Environment\n- Useful env vars: `JAVA_HOME`, `TEST_JAVA_HOME`, `BTRACE_TEST_DEBUG=true` (verbose integration tests), optional `BTRACE_HOME` when using the exploded dist.\n- Example exploded dist path: `btrace-dist/build/resources/main/v2.2.6/`.\n\n### Restricted/CI Environments\n- Prefer a workspace-local Gradle cache to avoid permission issues: set `GRADLE_USER_HOME=$(pwd)/.gradle-user`.\n- If network interfaces are restricted, force IPv4 to avoid wildcard IP detection errors: set `JAVA_TOOL_OPTIONS=\"-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false\"`.\n- Example: `GRADLE_USER_HOME=$(pwd)/.gradle-user JAVA_TOOL_OPTIONS=\"-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false\" ./gradlew :btrace-dist:buildZip -x test`\n\n## Common Patterns & Lessons Learned\n\n### Adding New Classes\n1. **Determine the section**: Is the class used by agent, client, or both?\n   - Agent only → prepareAgentClassdata include pattern\n   - Client only → prepareClientClassdata include pattern\n   - Both → prepareSharedClassdata include pattern\n2. **Update build.gradle**: Add include pattern in the appropriate task\n3. **Rebuild and test**: `./gradlew clean :btrace-dist:btraceJar && ./gradlew -Pintegration test`\n\n### Dependency Relocation\n- All third-party dependencies are relocated to `org.openjdk.btrace.libs.*`\n- Relocations happen in `allClassesShadow` task using Shadow plugin\n- Common relocations: ASM, SLF4J, JCTools\n- After relocation, classes are extracted and masked in prepare*Classdata tasks\n\n### Build Simplification Wins\n- **Before**: Separate agent.jar, client.jar, boot.jar, uber.jar (4 artifacts)\n- **After**: Single btrace.jar with masked sections (1 artifact)\n- **Result**: Simpler build, smaller distribution, easier maintenance\n\n### ClassLoader Isolation\n- Bootstrap classes can see everything (including masked sections via MaskedClassLoader)\n- Application classes cannot see masked sections (isolation prevents conflicts)\n- Masked classes in agent mode cannot see masked classes in client mode (intentional isolation)\n- Shared section solves cross-mode visibility when needed (e.g., command serialization)\n\n## Hard rules\n- Never commit changes unless they are fully tested or you are explicitly asked to commit\n- Do not use FQNs directly! Always import types and use simple type names in the code!\n- When adding classes to masked jar, always consider: agent-only, client-only, or shared?\n- Rebuild the distribution after any changes to masked jar structure: `./gradlew clean :btrace-dist:btraceJar`\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to BTrace\n\nThanks for your interest in contributing! This guide covers local development, running tests, Gradle tips, and common troubleshooting.\n\nNote: Pull requests can only be accepted from signers of the Oracle Contributor Agreement (OCA). See the project README for details.\n\n## Local Development\n\n- JDK: Use a reasonably recent JDK (11+ recommended). The project targets a broad range but tests run comfortably on 11/17.\n- Wrapper: Use the bundled `./gradlew` wrapper. It will download the pinned Gradle version if needed.\n- Local Gradle cache (optional but recommended):\n  - macOS/Linux: `export GRADLE_USER_HOME=\"$PWD/.gradle-home\"`\n  - Windows (PowerShell): `$env:GRADLE_USER_HOME = \"$PWD/.gradle-home\"`\n\n## Running Tests\n\n- All unit tests (skip integration tests):\n  ```sh\n  ./gradlew --no-daemon test -x integration-tests:test\n  ```\n\n- Per-module tests:\n  - Runtime: `./gradlew :btrace-runtime:test`\n  - Extension: `./gradlew :btrace-extension:test`\n  - Compiler: `./gradlew :btrace-compiler:test`\n  - Instr: `./gradlew :btrace-instr:test`\n\n- Update instrumentor goldens when bytecode output changes:\n  ```sh\n  ./gradlew test -PupdateTestData\n  ```\n\n- Integration tests (spawn JVMs, exercise agent and extensions):\n  ```sh\n  ./gradlew --no-daemon integration-tests:test\n  ```\n  - If tests fail due to denied privileged extensions, pass a policy file to the tested JVMs:\n    - Create `permissions.properties`:\n      ```properties\n      allowPrivileged=true\n      allowExtensions=btrace-metrics,btrace-utils\n      ```\n    - Export path: `export BTRACE_PERMS=$PWD/permissions.properties`\n    - Run Gradle with: `-Dbtrace.permissions=$BTRACE_PERMS`\n\n## Gradle Tips\n\n- Prefer IPv4 if your environment has unusual local IP settings (helps Gradle select a wildcard address):\n  ```sh\n  export GRADLE_OPTS=\"-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false\"\n  ```\n- Enable Gradle debug output for flakiness: add `--info` or `--debug`.\n- Run a single test class/method:\n  ```sh\n  ./gradlew :btrace-extension:test --tests org.openjdk.btrace.extension.ExtensionBridgeImplPolicyTest\n  ./gradlew :btrace-runtime:test --tests \"*ExtensionIndyShimIndexTest.resolvesNoopShimFromIndex\"\n  ```\n\n## Troubleshooting\n\n- Gradle wrapper needs to download Gradle: ensure network is allowed once; subsequent runs use the local cache under `.gradle-home`.\n- Error: `Could not determine a usable wildcard IP for this machine`:\n  - Set the IPv4 flags shown above or ensure local networking is available.\n- Permission errors when Gradle writes outside the workspace:\n  - Use a local Gradle cache via `GRADLE_USER_HOME` as shown above.\n- Integration tests failing with permissions denied:\n  - Provide a policy file and pass it via `-Dbtrace.permissions=/path/to/permissions.properties`.\n\n## Code Style & Scope\n\n- Keep changes focused and minimal; align with existing code style.\n- Update docs when changing user-visible behavior.\n- Prefer clear separation of concerns and small helpers over inlined, complex logic.\n- Avoid introducing new dependencies without discussion.\n\n## Submitting a PR\n\n1. Fork the repo and branch from `develop` (unless otherwise agreed).\n2. Make your changes and run tests locally.\n3. If instrumentor behavior changed, update goldens (`-PupdateTestData`) and include them in your commit.\n4. Submit a PR with a concise description of the change, rationale, and any follow-ups.\n\nHappy tracing!\n\n"
  },
  {
    "path": "LICENSE",
    "content": "The GNU General Public License (GPL)\n\nVersion 2, June 1991\n\nCopyright (C) 1989, 1991 Free Software Foundation, Inc.\n59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\nEveryone is permitted to copy and distribute verbatim copies of this license\ndocument, but changing it is not allowed.\n\nPreamble\n\nThe licenses for most software are designed to take away your freedom to share\nand change it.  By contrast, the GNU General Public License is intended to\nguarantee your freedom to share and change free software--to make sure the\nsoftware is free for all its users.  This General Public License applies to\nmost of the Free Software Foundation's software and to any other program whose\nauthors commit to using it.  (Some other Free Software Foundation software is\ncovered by the GNU Library General Public License instead.) You can apply it to\nyour programs, too.\n\nWhen we speak of free software, we are referring to freedom, not price.  Our\nGeneral Public Licenses are designed to make sure that you have the freedom to\ndistribute copies of free software (and charge for this service if you wish),\nthat you receive source code or can get it if you want it, that you can change\nthe software or use pieces of it in new free programs; and that you know you\ncan do these things.\n\nTo protect your rights, we need to make restrictions that forbid anyone to deny\nyou these rights or to ask you to surrender the rights.  These restrictions\ntranslate to certain responsibilities for you if you distribute copies of the\nsoftware, or if you modify it.\n\nFor example, if you distribute copies of such a program, whether gratis or for\na fee, you must give the recipients all the rights that you have.  You must\nmake sure that they, too, receive or can get the source code.  And you must\nshow them these terms so they know their rights.\n\nWe protect your rights with two steps: (1) copyright the software, and (2)\noffer you this license which gives you legal permission to copy, distribute\nand/or modify the software.\n\nAlso, for each author's protection and ours, we want to make certain that\neveryone understands that there is no warranty for this free software.  If the\nsoftware is modified by someone else and passed on, we want its recipients to\nknow that what they have is not the original, so that any problems introduced\nby others will not reflect on the original authors' reputations.\n\nFinally, any free program is threatened constantly by software patents.  We\nwish to avoid the danger that redistributors of a free program will\nindividually obtain patent licenses, in effect making the program proprietary.\nTo prevent this, we have made it clear that any patent must be licensed for\neveryone's free use or not licensed at all.\n\nThe precise terms and conditions for copying, distribution and modification\nfollow.\n\nTERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n0. This License applies to any program or other work which contains a notice\nplaced by the copyright holder saying it may be distributed under the terms of\nthis General Public License.  The \"Program\", below, refers to any such program\nor work, and a \"work based on the Program\" means either the Program or any\nderivative work under copyright law: that is to say, a work containing the\nProgram or a portion of it, either verbatim or with modifications and/or\ntranslated into another language.  (Hereinafter, translation is included\nwithout limitation in the term \"modification\".) Each licensee is addressed as\n\"you\".\n\nActivities other than copying, distribution and modification are not covered by\nthis License; they are outside its scope.  The act of running the Program is\nnot restricted, and the output from the Program is covered only if its contents\nconstitute a work based on the Program (independent of having been made by\nrunning the Program).  Whether that is true depends on what the Program does.\n\n1. You may copy and distribute verbatim copies of the Program's source code as\nyou receive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice and\ndisclaimer of warranty; keep intact all the notices that refer to this License\nand to the absence of any warranty; and give any other recipients of the\nProgram a copy of this License along with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and you may\nat your option offer warranty protection in exchange for a fee.\n\n2. You may modify your copy or copies of the Program or any portion of it, thus\nforming a work based on the Program, and copy and distribute such modifications\nor work under the terms of Section 1 above, provided that you also meet all of\nthese conditions:\n\n    a) You must cause the modified files to carry prominent notices stating\n    that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in whole or\n    in part contains or is derived from the Program or any part thereof, to be\n    licensed as a whole at no charge to all third parties under the terms of\n    this License.\n\n    c) If the modified program normally reads commands interactively when run,\n    you must cause it, when started running for such interactive use in the\n    most ordinary way, to print or display an announcement including an\n    appropriate copyright notice and a notice that there is no warranty (or\n    else, saying that you provide a warranty) and that users may redistribute\n    the program under these conditions, and telling the user how to view a copy\n    of this License.  (Exception: if the Program itself is interactive but does\n    not normally print such an announcement, your work based on the Program is\n    not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If identifiable\nsections of that work are not derived from the Program, and can be reasonably\nconsidered independent and separate works in themselves, then this License, and\nits terms, do not apply to those sections when you distribute them as separate\nworks.  But when you distribute the same sections as part of a whole which is a\nwork based on the Program, the distribution of the whole must be on the terms\nof this License, whose permissions for other licensees extend to the entire\nwhole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest your\nrights to work written entirely by you; rather, the intent is to exercise the\nright to control the distribution of derivative or collective works based on\nthe Program.\n\nIn addition, mere aggregation of another work not based on the Program with the\nProgram (or with a work based on the Program) on a volume of a storage or\ndistribution medium does not bring the other work under the scope of this\nLicense.\n\n3. You may copy and distribute the Program (or a work based on it, under\nSection 2) in object code or executable form under the terms of Sections 1 and\n2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable source\n    code, which must be distributed under the terms of Sections 1 and 2 above\n    on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three years, to\n    give any third party, for a charge no more than your cost of physically\n    performing source distribution, a complete machine-readable copy of the\n    corresponding source code, to be distributed under the terms of Sections 1\n    and 2 above on a medium customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer to\n    distribute corresponding source code.  (This alternative is allowed only\n    for noncommercial distribution and only if you received the program in\n    object code or executable form with such an offer, in accord with\n    Subsection b above.)\n\nThe source code for a work means the preferred form of the work for making\nmodifications to it.  For an executable work, complete source code means all\nthe source code for all modules it contains, plus any associated interface\ndefinition files, plus the scripts used to control compilation and installation\nof the executable.  However, as a special exception, the source code\ndistributed need not include anything that is normally distributed (in either\nsource or binary form) with the major components (compiler, kernel, and so on)\nof the operating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the source\ncode from the same place counts as distribution of the source code, even though\nthird parties are not compelled to copy the source along with the object code.\n\n4. You may not copy, modify, sublicense, or distribute the Program except as\nexpressly provided under this License.  Any attempt otherwise to copy, modify,\nsublicense or distribute the Program is void, and will automatically terminate\nyour rights under this License.  However, parties who have received copies, or\nrights, from you under this License will not have their licenses terminated so\nlong as such parties remain in full compliance.\n\n5. You are not required to accept this License, since you have not signed it.\nHowever, nothing else grants you permission to modify or distribute the Program\nor its derivative works.  These actions are prohibited by law if you do not\naccept this License.  Therefore, by modifying or distributing the Program (or\nany work based on the Program), you indicate your acceptance of this License to\ndo so, and all its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n6. Each time you redistribute the Program (or any work based on the Program),\nthe recipient automatically receives a license from the original licensor to\ncopy, distribute or modify the Program subject to these terms and conditions.\nYou may not impose any further restrictions on the recipients' exercise of the\nrights granted herein.  You are not responsible for enforcing compliance by\nthird parties to this License.\n\n7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues), conditions\nare imposed on you (whether by court order, agreement or otherwise) that\ncontradict the conditions of this License, they do not excuse you from the\nconditions of this License.  If you cannot distribute so as to satisfy\nsimultaneously your obligations under this License and any other pertinent\nobligations, then as a consequence you may not distribute the Program at all.\nFor example, if a patent license would not permit royalty-free redistribution\nof the Program by all those who receive copies directly or indirectly through\nyou, then the only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply and\nthe section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any patents or\nother property right claims or to contest validity of any such claims; this\nsection has the sole purpose of protecting the integrity of the free software\ndistribution system, which is implemented by public license practices.  Many\npeople have made generous contributions to the wide range of software\ndistributed through that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing to\ndistribute software through any other system and a licensee cannot impose that\nchoice.\n\nThis section is intended to make thoroughly clear what is believed to be a\nconsequence of the rest of this License.\n\n8. If the distribution and/or use of the Program is restricted in certain\ncountries either by patents or by copyrighted interfaces, the original\ncopyright holder who places the Program under this License may add an explicit\ngeographical distribution limitation excluding those countries, so that\ndistribution is permitted only in or among countries not thus excluded.  In\nsuch case, this License incorporates the limitation as if written in the body\nof this License.\n\n9. The Free Software Foundation may publish revised and/or new versions of the\nGeneral Public License from time to time.  Such new versions will be similar in\nspirit to the present version, but may differ in detail to address new problems\nor concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any later\nversion\", you have the option of following the terms and conditions either of\nthat version or of any later version published by the Free Software Foundation.\nIf the Program does not specify a version number of this License, you may\nchoose any version ever published by the Free Software Foundation.\n\n10. If you wish to incorporate parts of the Program into other free programs\nwhose distribution conditions are different, write to the author to ask for\npermission.  For software which is copyrighted by the Free Software Foundation,\nwrite to the Free Software Foundation; we sometimes make exceptions for this.\nOur decision will be guided by the two goals of preserving the free status of\nall derivatives of our free software and of promoting the sharing and reuse of\nsoftware generally.\n\nNO WARRANTY\n\n11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR\nTHE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN OTHERWISE\nSTATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE\nPROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,\nINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND\nPERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE,\nYOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL\nANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE\nPROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR\nINABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA\nBEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER\nOR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n\nEND OF TERMS AND CONDITIONS\n\nHow to Apply These Terms to Your New Programs\n\nIf you develop a new program, and you want it to be of the greatest possible\nuse to the public, the best way to achieve this is to make it free software\nwhich everyone can redistribute and change under these terms.\n\nTo do so, attach the following notices to the program.  It is safest to attach\nthem to the start of each source file to most effectively convey the exclusion\nof warranty; and each file should have at least the \"copyright\" line and a\npointer to where the full notice is found.\n\n    One line to give the program's name and a brief idea of what it does.\n\n    Copyright (C) <year> <name of author>\n\n    This program is free software; you can redistribute it and/or modify it\n    under the terms of the GNU General Public License as published by the Free\n    Software Foundation; either version 2 of the License, or (at your option)\n    any later version.\n\n    This program is distributed in the hope that it will be useful, but WITHOUT\n    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n    more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc., 59\n    Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this when it\nstarts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author Gnomovision comes\n    with ABSOLUTELY NO WARRANTY; for details type 'show w'.  This is free\n    software, and you are welcome to redistribute it under certain conditions;\n    type 'show c' for details.\n\nThe hypothetical commands 'show w' and 'show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may be\ncalled something other than 'show w' and 'show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.  Here\nis a sample; alter the names:\n\n    Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n    'Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n    signature of Ty Coon, 1 April 1989\n\n    Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General Public\nLicense instead of this License.\n\n\n\"CLASSPATH\" EXCEPTION TO THE GPL\n\nCertain source files distributed by Oracle America and/or its affiliates are\nsubject to the following clarification and special exception to the GPL, but\nonly where Oracle has expressly included in the particular source file's header\nthe words \"Oracle designates this particular file as subject to the \"Classpath\"\nexception as provided by Oracle in the LICENSE file that accompanied this code.\"\n\n    Linking this library statically or dynamically with other modules is making\n    a combined work based on this library.  Thus, the terms and conditions of\n    the GNU General Public License cover the whole combination.\n\n    As a special exception, the copyright holders of this library give you\n    permission to link this library with independent modules to produce an\n    executable, regardless of the license terms of these independent modules,\n    and to copy and distribute the resulting executable under terms of your\n    choice, provided that you also meet, for each linked independent module,\n    the terms and conditions of the license of that module.  An independent\n    module is a module which is not derived from or based on this library.  If\n    you modify this library, you may extend this exception to your version of\n    the library, but you are not obligated to do so.  If you do not wish to do\n    so, delete this exception statement from your version.\n\n\n[All 3rd party libraries licenses are listed in LICENSE-3RD-PARTY.txt file]"
  },
  {
    "path": "README.md",
    "content": "# BTrace\n\n**Safe, dynamic tracing for Java applications**\n\n[![CI](https://github.com/btraceio/btrace/workflows/BTrace%20CI%2FCD/badge.svg?branch=develop)](https://github.com/btraceio/btrace/actions)\n[![Release](https://img.shields.io/github/v/release/btraceio/btrace?sort=semver)](https://github.com/btraceio/btrace/releases/latest)\n[![codecov](https://codecov.io/github/btraceio/btrace/coverage.svg?branch=develop)](https://codecov.io/github/btraceio/btrace?branch=develop)\n\nBTrace dynamically instruments running Java applications to inject tracing code at runtime. No restarts. No recompilation. Production-safe.\n\n> **Quick links:** [Quick Reference](docs/QuickReference.md) · [Step-by-Step Tutorial](docs/GettingStarted.md)\n\n---\n\n## Why BTrace?\n\n- **Zero downtime** - Attach to running JVMs without restart\n- **Production safe** - Verified scripts can't crash your application\n- **Flexible probes** - Method entry/exit, timings, field access, allocations\n- **Low overhead** - Bytecode injection with minimal performance impact\n\n---\n\n## Get Started in 30 Seconds\n\n```sh\n# Install via JBang (easiest)\ncurl -Ls https://sh.jbang.dev | bash -s - app setup\n\n# Add the BTrace JBang catalog (one time)\njbang catalog add --name btraceio https://raw.githubusercontent.com/btraceio/jbang-catalog/main/jbang-catalog.json\n\n# Trace slow methods in your running app\njbang btrace@btraceio -n 'com.myapp.*::* @return if duration>100ms { print method, duration }' $(pgrep -f myapp)\n```\n\n---\n\n## Trace Anything\n\n**Method timing:**\n```sh\nbtrace -n 'java.sql.Statement::execute* @return { print method, duration }' <PID>\n```\n\n**Exception tracking:**\n```sh\nbtrace -n 'java.lang.Exception::<init> @return { print self, stack(5) }' <PID>\n```\n\n**Custom probes:**\n```java\n@BTrace public class Trace {\n    @OnMethod(clazz = \"com.example.OrderService\", method = \"checkout\")\n    public static void onCheckout(@Self Object self, @Duration long ns) {\n        println(strcat(\"checkout: \", str(ns/1_000_000) + \"ms\"));\n    }\n}\n```\n\nSee the [Oneliner Guide](docs/OnelinerGuide.md) for complete syntax.\n\n---\n\n## Install\n\n```sh\n# JBang (recommended - zero installation)\njbang catalog add --name btraceio https://raw.githubusercontent.com/btraceio/jbang-catalog/main/jbang-catalog.json\njbang btrace@btraceio <PID> script.java\n\n# SDKMan\nsdk install btrace\n\n# Manual download\ncurl -LO https://github.com/btraceio/btrace/releases/latest/download/btrace-bin.tar.gz\n```\n\nSee [Installation Guide](docs/GettingStarted.md#installation) for Docker, package managers, and more options.\n\n---\n\n## Documentation\n\n| Resource | Description |\n|----------|-------------|\n| [Quick Reference](docs/QuickReference.md) | Cheat sheet for experienced users |\n| [Getting Started](docs/GettingStarted.md) | Step-by-step first trace tutorial |\n| [Full Tutorial](docs/BTraceTutorial.md) | Complete walkthrough of all features |\n| [Oneliners](docs/OnelinerGuide.md) | DTrace-style quick probes |\n| [Extensions](docs/BTraceExtensionDevelopmentGuide.md) | StatsD, custom integrations |\n| [Documentation Hub](docs/README.md) | All docs and guides |\n\n---\n\n## Building from Source\n\n```sh\ngit clone https://github.com/btraceio/btrace.git\ncd btrace\n./gradlew :btrace-dist:build\n```\n\nSee [CLAUDE.md](CLAUDE.md) for development setup and architecture.\n\n---\n\n## Community & Contributing\n\n**Get help:** [Slack](http://btrace.slack.com/) · [Gitter](https://gitter.im/btraceio/btrace) · [GitHub Issues](https://github.com/btraceio/btrace/issues)\n\n**Contribute:** Pull requests require signing the [Oracle Contributor Agreement](https://oca.opensource.oracle.com/).\n\n---\n\n## License\n\nGPLv2 with Classpath Exception. See [LICENSE](LICENSE).\n\n---\n\n**Credits:** Built with [ASM](http://asm.ow2.org/), [JCTools](https://github.com/JCTools/JCTools), [hppcrt](https://github.com/vsonnier/hppcrt). Optimized with [JProfiler](http://www.ej-technologies.com/products/jprofiler/overview.html).\n"
  },
  {
    "path": "benchmarks/agent-benchmark/build.gradle",
    "content": "plugins {\n  id 'java'\n  alias(libs.plugins.jmh)\n}\n\ndescription 'A JMH benchmark to assert the overhead imposed by various types of BTrace instrumentation.'\n\ndef env = System.getenv()\ndef javaHome = env['JAVA_HOME']\n\ndependencies {\n  implementation project(path: \":btrace-dist\", configuration: \"shadow\")\n  implementation project(\":btrace-compiler\")\n  jmh tasks.getByPath(':btrace-dist:btraceJar').outputs.getFiles()\n\n  jmh libs.jmh\n  jmh libs.jmh.annprocess\n}\n\ntask btracec(type: JavaExec) {\n  group 'Build'\n  inputs.files 'src/main/resources/scripts'\n  outputs.dir buildDir.toPath().resolve(\"classes/java/main\")\n\n  environment('BTRACE_HOME', \"$projectDir\")\n  classpath configurations.runtimeClasspath\n  mainClass = 'org.openjdk.btrace.compiler.Compiler'\n  args '-d'\n  args \"${buildDir}/classes/java/main/\"\n  args '-packext'\n  args 'btclass'\n  args fileTree(dir: \"src/jmh/btrace\", include: 'TraceScript.java')\n}\ncompileJmhJava.dependsOn btracec\njmhClasses.dependsOn btracec\n\njmhJar {\n  include 'META-INF/BenchmarkList'\n  include 'META-INF/CompilerHints'\n  include 'org/openjdk/jmh/**'\n  include 'org/openjdk/btrace/bench/**/*.class'\n  include 'org/openjdk/btrace/generated/**/*'\n  include \"joptsimple/**\"\n  include \"org/apache/**\"\n  include 'jmh*'\n  include 'benchmark/**'\n  include '*.btclass'\n}\n\njmh {\n  warmupIterations = 5\n  iterations = 10\n  fork = 2\n  jvm = \"${env['JAVA_HOME']}/bin/java\"\n  duplicateClassesStrategy = DuplicatesStrategy.WARN\n  def agentJarPath = tasks.getByPath(':btrace-dist:btraceJar').outputs.getFiles().getSingleFile()\n  def scriptPath = buildDir.toPath().resolve('classes/java/main/TraceScript.btclass')\n  def agent = \"-javaagent:${agentJarPath}=stdout=false,noServer=true,debug=false,script=${scriptPath}\"\n  jvmArgsAppend = [\"-Djmh.basedir=${buildDir.getParentFile()}\", \"-Dproject.version=${project.version}\", \"-Xmx128m\", \"-agentpath:/tmp/libasyncProfiler.dylib=start,event=cpu,jfr=7,file=/tmp/btrace.jfr\", \"${agent}\"]\n  includes = ['.*BTraceBench.*']\n  profilers = ['stack']\n}"
  },
  {
    "path": "benchmarks/agent-benchmark/src/jmh/btrace/TraceScript.java",
    "content": "import static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Sampled;\n\n@BTrace\npublic class TraceScript {\n  @OnMethod(clazz = \"benchmark.BTraceBench\", method = \"testInstrumentedMethod\")\n  public static void onMethodEntryEmpty(@ProbeClassName String pcn, @ProbeMethodName String pmn) {}\n\n  @OnMethod(\n      clazz = \"benchmark.BTraceBench\",\n      method = \"testInstrumentedMethodLevelNoMatch\",\n      enableAt = @Level(\"100\"))\n  public static void onMethodEntryEmptyLevelNoMatch(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {}\n\n  @OnMethod(clazz = \"benchmark.BTraceBench\", method = \"testInstrumentedMethodSampled\")\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void onMethodEntryEmptySampled(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {}\n\n  @OnMethod(\n      clazz = \"benchmark.BTraceBench\",\n      method = \"testInstrDuration\",\n      location = @Location(Kind.RETURN))\n  public static void onMethodRetDuration(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn, @Duration long dur) {}\n\n  @OnMethod(\n      clazz = \"benchmark.BTraceBench\",\n      method = \"testInstrDurationSampled\",\n      location = @Location(Kind.RETURN))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void onMethodRetDurationSampled(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn, @Duration long dur) {}\n\n  @OnMethod(\n      clazz = \"benchmark.BTraceBench\",\n      method = \"testInstrDurationSampledAdaptive\",\n      location = @Location(Kind.RETURN))\n  @Sampled\n  public static void onMethodRetDurationSampledAdaptive(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn, @Duration long dur) {}\n\n  @OnMethod(clazz = \"benchmark.BTraceBench\", method = \"testInstrumentedMethodPrintln1\")\n  public static void onMethodEntryPrintln1(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {\n    println(pcn);\n  }\n\n  @OnMethod(clazz = \"benchmark.BTraceBench\", method = \"testInstrumentedMethodPrintln1Sampled\")\n  @Sampled\n  public static void onMethodEntryPrintln1Sampled(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {\n    println(pcn);\n  }\n\n  @OnMethod(clazz = \"benchmark.BTraceBench\", method = \"testInstrumentedMethodPrintln2\")\n  public static void onMethodEntryPrintln2(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {\n    println(pcn);\n    println(pmn);\n  }\n\n  @OnMethod(clazz = \"benchmark.BTraceBench\", method = \"testInstrumentedMethodPrintln3\")\n  public static void onMethodEntryPrintln3(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {\n    println(pcn);\n    println(pmn);\n    println(pmn);\n  }\n\n  @OnMethod(clazz = \"benchmark.BTraceBench\", method = \"testInstrumentedMethodPrintln24\")\n  public static void onMethodEntryPrintln24(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n  }\n}\n"
  },
  {
    "path": "benchmarks/agent-benchmark/src/jmh/java/benchmark/BTraceBench.java",
    "content": "/*\n * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage benchmark;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.nio.file.FileSystem;\nimport java.nio.file.FileSystems;\nimport java.nio.file.FileVisitResult;\nimport java.nio.file.FileVisitor;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardCopyOption;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.util.Random;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.openjdk.btrace.instr.MethodTracker;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Measurement;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.Threads;\nimport org.openjdk.jmh.annotations.Warmup;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\n@State(Scope.Thread)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Fork(1)\n@BenchmarkMode(Mode.AverageTime)\npublic class BTraceBench {\n\n  private static class BTraceConfig {\n\n    private final String agentJar;\n    private final String scriptPath;\n    private final Path tmpRoot;\n\n    private static final FileVisitor<Path> DEL_TREE =\n        new FileVisitor<Path>() {\n          @Override\n          public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)\n              throws IOException {\n            return FileVisitResult.CONTINUE;\n          }\n\n          @Override\n          public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)\n              throws IOException {\n            Files.delete(file);\n            return FileVisitResult.CONTINUE;\n          }\n\n          @Override\n          public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {\n            return FileVisitResult.TERMINATE;\n          }\n\n          @Override\n          public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {\n            Files.delete(dir);\n            return FileVisitResult.CONTINUE;\n          }\n        };\n\n    public BTraceConfig(Path tmpRoot, String agentJar, String scriptPath) {\n      this.agentJar = agentJar;\n      this.scriptPath = scriptPath;\n      this.tmpRoot = tmpRoot;\n    }\n\n    public void cleanup() throws IOException {\n      Files.walkFileTree(tmpRoot, DEL_TREE);\n    }\n  }\n\n  long counter;\n  long sampleCounter;\n  long durCounter;\n\n  @Setup\n  public void setup() {\n    MethodTracker.registerCounter(1, 10);\n    MethodTracker.registerCounter(2, 50);\n    MethodTracker.registerCounter(3, 100);\n\n    Random r = new Random(System.currentTimeMillis());\n    sampleCounter = 0;\n    durCounter = 0;\n    counter = r.nextInt();\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testInstrumentedMethod() {\n    counter++;\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testInstrumentedMethodLevelNoMatch() {\n    counter++;\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testInstrumentedMethodSampled() {\n    counter++;\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testInstrumentedMethodPrintln1() {\n    counter++;\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testInstrumentedMethodPrintln1Sampled() {\n    counter++;\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testInstrumentedMethodPrintln2() {\n    counter++;\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testInstrumentedMethodPrintln3() {\n    counter++;\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testInstrumentedMethodPrintln24() {\n    counter++;\n  }\n\n  @Warmup(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testMethod() {\n    counter++;\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testInstrDuration() {\n    durCounter++;\n  }\n\n  public boolean x = true;\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testInstrDurationSampled() {\n    sampleCounter++;\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testInstrDurationSampledAdaptive() {\n    sampleCounter++;\n  }\n\n  //    @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  //    @Measurement(iterations = 5, time = 2000, timeUnit = TimeUnit.MILLISECONDS)\n  //    @Benchmark\n  //    public void testSendCommand() {\n  //        br.send(new OkayCommand());\n  //    }\n  //\n  //    @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  //    @Measurement(iterations = 5, time = 2000, timeUnit = TimeUnit.MILLISECONDS)\n  //    @Threads(2)\n  //    @Benchmark\n  //    public void testSendCommandMulti2() {\n  //        br.send(new OkayCommand());\n  //    }\n  //\n  //    @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  //    @Measurement(iterations = 5, time = 2000, timeUnit = TimeUnit.MILLISECONDS)\n  //    @Threads(4)\n  //    @Benchmark\n  //    public void testSendCommandMulti4() {\n  //        br.send(new OkayCommand());\n  //    }\n  //\n  //    @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  //    @Measurement(iterations = 5, time = 2000, timeUnit = TimeUnit.MILLISECONDS)\n  //    @Threads(8)\n  //    @Benchmark\n  //    public void testSendCommandMulti8() {\n  //        br.send(new OkayCommand());\n  //    }\n  //\n  //    @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  //    @Measurement(iterations = 5, time = 2000, timeUnit = TimeUnit.MILLISECONDS)\n  //    @Threads(16)\n  //    @Benchmark\n  //    public void testSendCommandMulti16() {\n  //        br.send(new OkayCommand());\n  //    }\n\n  long sampleHit10Checks = 0;\n  long sampleHit10Sampled = 0;\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 20, time = 100, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  @Threads(2)\n  public void testSampleHit10() {\n    sampleHit10Checks++;\n    if (MethodTracker.hit(1)) {\n      sampleHit10Sampled++;\n    }\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 20, time = 100, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  @Threads(2)\n  public void testSampleHit50() {\n    sampleHit10Checks++;\n    if (MethodTracker.hit(2)) {\n      sampleHit10Sampled++;\n    }\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 20, time = 100, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  @Threads(2)\n  public void testSampleHit100() {\n    sampleHit10Checks++;\n    if (MethodTracker.hit(3)) {\n      sampleHit10Sampled++;\n    }\n  }\n\n  @org.openjdk.jmh.annotations.TearDown\n  public void teardown() {\n    if (sampleHit10Checks > 0) {\n      System.err.println(\"=== testSampleHit10\");\n      System.err.println(\"#samples ~ \" + sampleHit10Sampled);\n      if (sampleHit10Sampled > 0) {\n        System.err.println(\"#sampling rate ~ \" + (sampleHit10Checks / sampleHit10Sampled));\n      }\n    }\n  }\n\n  public static void main(String[] args) throws Exception {\n    BTraceConfig bc = getConfig();\n    try {\n      Options opt =\n          new OptionsBuilder()\n              .addProfiler(\"stack\")\n//              .jvmArgsPrepend(\n//                  \"-javaagent:\"\n//                      + bc.agentJar\n//                      + \"=stdout=false,noServer=true,\"\n//                      + \"script=\"\n//                      + bc.scriptPath)\n              .include(\".*\" + BTraceBench.class.getSimpleName() + \".*test.*\")\n              .build();\n\n      new Runner(opt).run();\n    } finally {\n      bc.cleanup();\n    }\n  }\n\n  private static BTraceConfig getConfig() throws IOException {\n    FileSystem fs = FileSystems.getDefault();\n\n    Path distLibs = null;\n    String basedir = System.getProperty(\"jmh.basedir\");\n    String version = System.getProperty(\"project.version\");\n    String scriptPath = System.getProperty(\"script.path\");\n    Path root = null;\n    if (basedir == null) {\n      root = fs.getPath(\".\").toAbsolutePath();\n    } else {\n      root = Paths.get(basedir).getParent();\n    }\n    distLibs = root.resolve(\"btrace-dist/build/resources/main/\" + version + \"/libs\");\n\n    Path agentPath = distLibs.resolve(\"btrace-agent.jar\");\n    Path bootPath = distLibs.resolve(\"btrace-boot.jar\");\n\n    Path tmpDir = Files.createTempDirectory(\"btrace-bench-\");\n\n    Path targetPath =\n        Files.copy(\n            agentPath, tmpDir.resolve(\"btrace-agent.jar\"), StandardCopyOption.REPLACE_EXISTING);\n    Files.copy(bootPath, tmpDir.resolve(\"btrace-boot.jar\"), StandardCopyOption.REPLACE_EXISTING);\n\n    return new BTraceConfig(tmpDir, targetPath.toString(), scriptPath + \"/TraceScript.btclass\");\n  }\n}\n"
  },
  {
    "path": "benchmarks/runtime-benchmarks/build.gradle",
    "content": "plugins {\n  id 'java'\n  alias(libs.plugins.jmh)\n}\n\ndescription 'A JMH benchmark to assert the overhead imposed by various types of BTrace instrumentation.'\n\ndef env = System.getenv()\ndef javaHome = env['JAVA_HOME']\n\nconfigurations {\n  compilerDeps\n}\n\ndependencies {\n  implementation project(path: \":btrace-dist\", configuration: \"shadow\")\n  implementation project(\":btrace-compiler\")\n  jmh project(\":btrace-instr\")\n  jmh project(\":btrace-runtime\")\n  jmh project(\":btrace-extensions:btrace-statsd\")\n  jmh libs.jmh\n  jmh libs.jmh.annprocess\n  compilerDeps project(path: \":btrace-dist\", configuration: \"shadow\")\n  compilerDeps project(\":btrace-compiler\")\n}\n\ntask btracec(type: JavaExec) {\n  group 'Build'\n  inputs.files 'src/main/resources/scripts'\n  outputs.dir \"${buildDir}/classes/java/main\"\n\n  environment('BTRACE_HOME', \"$projectDir\")\n  classpath configurations.compilerDeps\n  mainClass = 'org.openjdk.btrace.compiler.Compiler'\n  args '-d'\n  args \"${buildDir}/classes/java/main/\"\n  args '-packext'\n  args 'btclass'\n  args fileTree(dir: \"src/jmh/btrace\", include: 'TraceScript.java')\n}\ncompileJmhJava.dependsOn btracec\njmhClasses.dependsOn btracec\n\njmhJar {\n  include 'META-INF/BenchmarkList'\n  include 'META-INF/CompilerHints'\n  include 'org/jctools/**/*'\n  include 'org/objectweb/asm/**'\n  include 'org/openjdk/jmh/**'\n  include 'org/openjdk/btrace/bench/**/*.class'\n  include \"org/openjdk/btrace/core/**\"\n  include \"org/openjdk/btrace/instr/**\"\n  include 'org/openjdk/btrace/generated/**/*'\n  include 'org/openjdk/btrace/runtime/**'\n  // no legacy services classes to package\n  include \"joptsimple/**\"\n  include \"org/apache/**\"\n  include '*.btclass'\n  include 'jmh*'\n}\n\njmh {\n  duplicateClassesStrategy = DuplicatesStrategy.WARN\n  jvmArgsAppend = [\"-Djmh.basedir=${project.buildDir.getParent()}\", \"-Dproject.version=${project.version}\"]\n//  jmhVersion = '1.27'\n  includes = ['org.openjdk.btrace.bench.ClassFilterBenchmark']\n  verbosity = 'EXTRA'\n}\n"
  },
  {
    "path": "benchmarks/runtime-benchmarks/src/jmh/btrace/TraceScript.java",
    "content": "import static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Sampled;\n\n@BTrace\npublic class TraceScript {\n  @OnMethod(clazz = \"org.openjdk.btrace.BTraceBench\", method = \"testInstrumentedMethod\")\n  public static void onMethodEntryEmpty(@ProbeClassName String pcn, @ProbeMethodName String pmn) {}\n\n  @OnMethod(\n      clazz = \"org.openjdk.btrace.BTraceBench\",\n      method = \"testInstrumentedMethodLevelNoMatch\",\n      enableAt = @Level(\"100\"))\n  public static void onMethodEntryEmptyLevelNoMatch(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {}\n\n  @OnMethod(clazz = \"org.openjdk.btrace.BTraceBench\", method = \"testInstrumentedMethodSampled\")\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void onMethodEntryEmptySampled(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {}\n\n  @OnMethod(\n      clazz = \"org.openjdk.btrace.BTraceBench\",\n      method = \"testInstrDuration\",\n      location = @Location(Kind.RETURN))\n  public static void onMethodRetDuration(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn, @Duration long dur) {}\n\n  @OnMethod(\n      clazz = \"org.openjdk.btrace.BTraceBench\",\n      method = \"testInstrDurationSampled\",\n      location = @Location(Kind.RETURN))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void onMethodRetDurationSampled(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn, @Duration long dur) {}\n\n  @OnMethod(\n      clazz = \"org.openjdk.btrace.BTraceBench\",\n      method = \"testInstrDurationSampledAdaptive\",\n      location = @Location(Kind.RETURN))\n  @Sampled\n  public static void onMethodRetDurationSampledAdaptive(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn, @Duration long dur) {}\n\n  @OnMethod(clazz = \"org.openjdk.btrace.BTraceBench\", method = \"testInstrumentedMethodPrintln1\")\n  public static void onMethodEntryPrintln1(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {\n    println(pcn);\n  }\n\n  @OnMethod(\n      clazz = \"org.openjdk.btrace.BTraceBench\",\n      method = \"testInstrumentedMethodPrintln1Sampled\")\n  @Sampled\n  public static void onMethodEntryPrintln1Sampled(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {\n    println(pcn);\n  }\n\n  @OnMethod(clazz = \"org.openjdk.btrace.BTraceBench\", method = \"testInstrumentedMethodPrintln2\")\n  public static void onMethodEntryPrintln2(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {\n    println(pcn);\n    println(pmn);\n  }\n\n  @OnMethod(clazz = \"org.openjdk.btrace.BTraceBench\", method = \"testInstrumentedMethodPrintln3\")\n  public static void onMethodEntryPrintln3(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {\n    println(pcn);\n    println(pmn);\n    println(pmn);\n  }\n\n  @OnMethod(clazz = \"org.openjdk.btrace.BTraceBench\", method = \"testInstrumentedMethodPrintln24\")\n  public static void onMethodEntryPrintln24(\n      @ProbeClassName String pcn, @ProbeMethodName String pmn) {\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n    println(pcn);\n    println(pmn);\n    println(pmn);\n  }\n}\n"
  },
  {
    "path": "benchmarks/runtime-benchmarks/src/jmh/java/org/openjdk/btrace/bench/ClassFilterBenchmark.java",
    "content": "/*\n * Copyright (c) 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\npackage org.openjdk.btrace.bench;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.concurrent.TimeUnit;\nimport org.openjdk.btrace.instr.ClassFilter;\nimport org.openjdk.btrace.instr.OnMethod;\nimport org.openjdk.jmh.annotations.*;\nimport org.openjdk.jmh.infra.Blackhole;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\n@State(Scope.Thread)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Fork(1)\n@BenchmarkMode(Mode.AverageTime)\npublic class ClassFilterBenchmark {\n  private static final String CLASS_A_PKG = \"org.openjdk.btrace.benchmark\";\n  private static final String CLASS_A_NAME = \"ClassA\";\n  private static final String CLASS_A = CLASS_A_PKG + \".\" + CLASS_A_NAME;\n\n  private ClassFilter cfSimple;\n  private ClassFilter cfRegexName;\n  private ClassFilter cfSubtype;\n\n  @Setup\n  public void setup() {\n    OnMethod simpleClassFilter = new OnMethod();\n    simpleClassFilter.setClazz(CLASS_A);\n\n    OnMethod regexNameFilter = new OnMethod();\n    regexNameFilter.setClazz(\"/.*\\\\.\" + CLASS_A_NAME + \"/\");\n\n    OnMethod subtypeFilter = new OnMethod();\n    subtypeFilter.setClazz(\"+java.util.List\");\n\n    cfSimple = new ClassFilter(Collections.singleton(simpleClassFilter));\n    cfRegexName = new ClassFilter(Collections.singleton(regexNameFilter));\n    cfSubtype = new ClassFilter(Collections.singleton(subtypeFilter));\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 1200, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testSimpleClassNameMatch(Blackhole bh) {\n    bh.consume(cfSimple.isNameMatching(CLASS_A));\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 1200, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testRegexNameMatch(Blackhole bh) {\n    bh.consume(cfRegexName.isNameMatching(CLASS_A));\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 1200, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testSubtypeMatch(Blackhole bh) {\n    bh.consume(cfSubtype.isCandidate(ArrayList.class));\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 1200, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testSubtypeNoMatch(Blackhole bh) {\n    bh.consume(cfSubtype.isCandidate(String.class));\n  }\n\n  public static void main(String[] args) throws Exception {\n    Options opt =\n        new OptionsBuilder()\n            .addProfiler(\"stack\")\n            .include(\".*\" + ClassFilterBenchmark.class.getSimpleName() + \".*test.*\")\n            .build();\n\n    new Runner(opt).run();\n  }\n}\n"
  },
  {
    "path": "benchmarks/runtime-benchmarks/src/jmh/java/org/openjdk/btrace/bench/DispatchBenchmark.java",
    "content": "/*\n * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.bench;\n\nimport java.lang.invoke.CallSite;\nimport java.lang.invoke.ConstantCallSite;\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.MethodType;\nimport java.lang.invoke.MutableCallSite;\nimport java.util.concurrent.TimeUnit;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Level;\nimport org.openjdk.jmh.annotations.Measurement;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.Warmup;\nimport org.openjdk.jmh.infra.Blackhole;\n\n/**\n * JMH benchmark measuring INVOKEDYNAMIC dispatch overhead as simulated by\n * {@link ConstantCallSite} — the mechanism used by {@code IndyDispatcher}.\n *\n * <p>Compares a plain static method call ({@link #baseline}) against dispatch\n * through a {@link ConstantCallSite} ({@link #instrumented}).\n */\n@State(Scope.Thread)\n@OutputTimeUnit(TimeUnit.NANOSECONDS)\n@Fork(1)\n@BenchmarkMode(Mode.AverageTime)\npublic class DispatchBenchmark {\n\n  private MethodHandle constantTarget;\n  private MethodHandle mutableTarget;\n\n  @Setup(Level.Trial)\n  public void setup() throws Exception {\n    // Build a ConstantCallSite targeting the static handler method, simulating what\n    // IndyDispatcher.bootstrap() produces.\n    MethodHandle mh =\n        MethodHandles.lookup()\n            .findStatic(\n                DispatchBenchmark.class,\n                \"probeHandler\",\n                MethodType.methodType(void.class, int.class));\n    CallSite cs = new ConstantCallSite(mh);\n    constantTarget = cs.dynamicInvoker();\n    MutableCallSite mcs = new MutableCallSite(mh.type());\n    mcs.setTarget(mh);\n    mutableTarget = mcs.dynamicInvoker();\n  }\n\n  /** Direct static call — baseline with zero dispatch overhead. */\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)\n  @Benchmark\n  public void baseline(Blackhole bh) {\n    probeHandler(42);\n  }\n\n  /** Dispatch through a ConstantCallSite — simulates IndyDispatcher-resolved call site. */\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)\n  @Benchmark\n  public void instrumented(Blackhole bh) throws Throwable {\n    constantTarget.invokeExact(42);\n  }\n\n  /**\n   * Dispatch through a MutableCallSite whose target is stable (set once, never re-linked).\n   * Simulates the IndyDispatcher-post-detach-safety variant. HotSpot should treat the target\n   * as @Stable and inline through it comparably to ConstantCallSite.\n   */\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)\n  @Benchmark\n  public void instrumentedMutable(Blackhole bh) throws Throwable {\n    mutableTarget.invokeExact(42);\n  }\n\n  /** Simulated probe handler method. */\n  public static void probeHandler(int value) {\n    // intentionally empty — we measure dispatch cost, not handler body cost\n  }\n}\n"
  },
  {
    "path": "benchmarks/runtime-benchmarks/src/jmh/java/org/openjdk/btrace/bench/OnMethodTemplateBenchmark.java",
    "content": "/*\n * Copyright (c) 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\npackage org.openjdk.btrace.bench;\n\nimport java.util.concurrent.TimeUnit;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.jmh.annotations.*;\nimport org.openjdk.jmh.infra.Blackhole;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\n@State(Scope.Thread)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Fork(1)\n@BenchmarkMode(Mode.AverageTime)\npublic class OnMethodTemplateBenchmark {\n  private ArgsMap argsMap;\n\n  @Setup\n  public void setup() {\n    argsMap = new ArgsMap(new String[] {\"arg1=val1\"});\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 1200, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testEmptyTemplate(Blackhole bh) {\n    bh.consume(argsMap.template(\"\"));\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 1200, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testMatchTemplate(Blackhole bh) {\n    bh.consume(argsMap.template(\"this-is-${arg1}\"));\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 1200, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testNoMatchTemplate(Blackhole bh) {\n    bh.consume(argsMap.template(\"this-is-${arg2}\"));\n  }\n\n  public static void main(String[] args) throws Exception {\n    Options opt =\n        new OptionsBuilder()\n            .addProfiler(\"stack\")\n            .include(\".*\" + OnMethodTemplateBenchmark.class.getSimpleName() + \".*test.*\")\n            .build();\n\n    new Runner(opt).run();\n  }\n}\n"
  },
  {
    "path": "benchmarks/runtime-benchmarks/src/jmh/java/org/openjdk/btrace/bench/ProbeLoadingBenchmark.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.bench;\n\nimport java.io.*;\nimport java.util.concurrent.TimeUnit;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.instr.BTraceProbe;\nimport org.openjdk.btrace.instr.BTraceProbeFactory;\nimport org.openjdk.jmh.annotations.*;\nimport org.openjdk.jmh.infra.Blackhole;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\n@State(Scope.Thread)\n@OutputTimeUnit(TimeUnit.MILLISECONDS)\n@Fork(1)\n@BenchmarkMode(Mode.AverageTime)\npublic class ProbeLoadingBenchmark {\n  private InputStream classStream;\n  private BTraceProbeFactory bpf;\n\n  @Setup(Level.Trial)\n  public void setup() throws Exception {\n    bpf = new BTraceProbeFactory(SharedSettings.GLOBAL);\n  }\n\n  @Setup(Level.Invocation)\n  public void setupRun() throws Exception {\n    classStream = ProbeLoadingBenchmark.class.getResourceAsStream(\"/TraceScript.btclass\");\n  }\n\n  @TearDown(Level.Invocation)\n  public void tearDownRun() throws Exception {\n    classStream.close();\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)\n  @Benchmark\n  public void testBTraceProbeNew(Blackhole bh) throws Exception {\n    BTraceProbe bp = bpf.createProbe(classStream);\n    if (bp == null) {\n      throw new NullPointerException();\n    }\n    bh.consume(bp);\n  }\n\n  public static void main(String[] args) throws Exception {\n    Options opt =\n        new OptionsBuilder()\n            .addProfiler(\"stack\")\n            .include(\".*\" + ProbeLoadingBenchmark.class.getSimpleName() + \".*test.*\")\n            .build();\n\n    new Runner(opt).run();\n  }\n}\n"
  },
  {
    "path": "benchmarks/runtime-benchmarks/src/jmh/java/org/openjdk/btrace/bench/ProfilerBenchmark.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.bench;\n\nimport java.util.concurrent.TimeUnit;\nimport org.openjdk.btrace.runtime.profiling.MethodInvocationProfiler;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Measurement;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.Threads;\nimport org.openjdk.jmh.annotations.Warmup;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\nimport org.openjdk.jmh.runner.options.VerboseMode;\n\n/**\n * Basic benchmark for the performance of {@linkplain MethodInvocationProfiler}\n *\n * @author Jaroslav Bachorik\n */\n@State(Scope.Thread)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Fork(1)\n@BenchmarkMode(Mode.AverageTime)\npublic class ProfilerBenchmark {\n  private MethodInvocationProfiler mip1;\n  private MethodInvocationProfiler mip2;\n\n  @Setup\n  public void setup() {\n    mip1 = new MethodInvocationProfiler(1);\n    mip2 = new MethodInvocationProfiler(500);\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  @Threads(1)\n  public void testOneMethodSingleThread() {\n    mip1.recordEntry(\"a\");\n    mip1.recordExit(\"a\", 1);\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  @Threads(1)\n  public void testTwoMethods01Thread() {\n    mip2.recordEntry(\"a\");\n    mip2.recordEntry(\"b\");\n    mip2.recordExit(\"b\", 10);\n    mip2.recordExit(\"a\", 1);\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  @Threads(2)\n  public void testTwoMethods02Threads() {\n    mip2.recordEntry(\"a\");\n    mip2.recordEntry(\"b\");\n    mip2.recordExit(\"b\", 10);\n    mip2.recordExit(\"a\", 1);\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  @Threads(4)\n  public void testTwoMethods04Threads() {\n    mip2.recordEntry(\"a\");\n    mip2.recordEntry(\"b\");\n    mip2.recordExit(\"b\", 10);\n    mip2.recordExit(\"a\", 1);\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  @Threads(8)\n  public void testTwoMethods08Threads() {\n    mip2.recordEntry(\"a\");\n    mip2.recordEntry(\"b\");\n    mip2.recordExit(\"b\", 10);\n    mip2.recordExit(\"a\", 1);\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  @Threads(16)\n  public void testTwoMethods16Threads() {\n    mip2.recordEntry(\"a\");\n    mip2.recordEntry(\"b\");\n    mip2.recordExit(\"b\", 10);\n    mip2.recordExit(\"a\", 1);\n  }\n\n  public static void main(String[] args) throws Exception {\n    Options opt =\n        new OptionsBuilder()\n            .addProfiler(\"stack\")\n            .verbosity(VerboseMode.NORMAL)\n            .include(\".*\" + ProfilerBenchmark.class.getSimpleName() + \".*test.*\")\n            .build();\n\n    new Runner(opt).run();\n  }\n}\n"
  },
  {
    "path": "benchmarks/runtime-benchmarks/src/jmh/java/org/openjdk/btrace/bench/StatsdBenchmark.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.bench;\n\nimport java.util.concurrent.TimeUnit;\nimport org.openjdk.btrace.statsd.Statsd;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Measurement;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.Threads;\nimport org.openjdk.jmh.annotations.Warmup;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\n/**\n * Basic benchmark for the performance of {@linkplain Statsd}\n *\n * @author Jaroslav Bachorik\n */\n@State(Scope.Thread)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Fork(1)\n@BenchmarkMode(Mode.AverageTime)\npublic class StatsdBenchmark {\n  private Statsd c;\n\n  @Setup\n  public void setup() {\n    // Inline no-op impl — the benchmark measures dispatch through the extension API,\n    // not the network-layer Statsd implementation.\n    c = new Statsd() {\n      @Override public void increment(String name) {}\n      @Override public void increment(String name, String tags) {}\n    };\n  }\n\n  @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  @Threads(1)\n  public void testIncrement_1() {\n    c.increment(\"g1\");\n  }\n\n  public static void main(String[] args) throws Exception {\n    Options opt =\n        new OptionsBuilder()\n            .addProfiler(\"stack\")\n            .include(\".*\" + StatsdBenchmark.class.getSimpleName() + \".*test.*\")\n            .build();\n\n    new Runner(opt).run();\n  }\n}\n"
  },
  {
    "path": "benchmarks/runtime-benchmarks/src/jmh/java/org/openjdk/btrace/bench/StringOpBenchmark.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.bench;\n\nimport java.util.concurrent.TimeUnit;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Level;\nimport org.openjdk.jmh.annotations.Measurement;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.Warmup;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\n@State(Scope.Thread)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Fork(1)\n@BenchmarkMode(Mode.AverageTime)\npublic class StringOpBenchmark {\n  private static final String STRING_PART = \"h\";\n\n  StringBuilder sb;\n  String st;\n  String res;\n\n  @Setup\n  public void setup() {\n    st = \"\";\n  }\n\n  @Setup(Level.Invocation)\n  public void setupEach() {\n    sb = new StringBuilder();\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 1200, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testStringBuilder() {\n    sb.append(STRING_PART).append(STRING_PART);\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 1200, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testStringPlus() {\n    res = st + STRING_PART + STRING_PART;\n  }\n\n  @Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)\n  @Measurement(iterations = 5, time = 1200, timeUnit = TimeUnit.MILLISECONDS)\n  @Benchmark\n  public void testStrCat() {\n    res = st.concat(STRING_PART).concat(STRING_PART);\n  }\n\n  public static void main(String[] args) throws Exception {\n    Options opt =\n        new OptionsBuilder()\n            .addProfiler(\"gc\")\n            .include(\".*\" + StringOpBenchmark.class.getSimpleName() + \".*test.*\")\n            .build();\n\n    new Runner(opt).run();\n  }\n}\n"
  },
  {
    "path": "btrace-agent/build.gradle",
    "content": "compileJava {\n    // Keep Java 8 compatibility while accessing JDK internal APIs\n    options.fork = true\n    options.forkOptions.jvmArgs += [\n        '--add-exports', 'jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED'\n    ]\n}\n\njavadoc {\n    // Javadoc also needs access to internal APIs - but Java 8 javadoc doesn't support --add-exports\n    // So we exclude the file that uses internal APIs from javadoc generation\n    exclude '**/PerfReaderImpl.java'\n}\n\ndependencies {\n    implementation libs.slf4j\n    implementation libs.asm\n\n    def toolsJar = getToolsJar();\n    if (toolsJar.getAsFile().exists()) {\n        runtimeOnly files(\"${toolsJar}\")\n    }\n    implementation project(':btrace-core')\n    implementation project(':btrace-runtime')\n    implementation project(':btrace-instr')\n    implementation project(':btrace-extension')\n}\n\n// Exclude sources that rely on JDK-internal modules from Javadoc to avoid missing-package errors\ntasks.named('javadoc').configure {\n    exclude 'org/openjdk/btrace/agent/PerfReaderImpl.java'\n}\n"
  },
  {
    "path": "btrace-agent/src/main/java/org/openjdk/btrace/agent/Client.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.agent;\n\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassWriter;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntimeBridge;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.openjdk.btrace.core.comm.ErrorCommand;\nimport org.openjdk.btrace.core.comm.ExitCommand;\nimport org.openjdk.btrace.core.comm.InstrumentCommand;\nimport org.openjdk.btrace.core.comm.MessageCommand;\nimport org.openjdk.btrace.core.comm.RenameCommand;\nimport org.openjdk.btrace.core.comm.RetransformationStartNotification;\nimport org.openjdk.btrace.core.comm.StatusCommand;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.core.extensions.PermissionSet;\nimport org.openjdk.btrace.extension.ExtensionDescriptorDTO;\nimport org.openjdk.btrace.extension.ExtensionLoader;\nimport org.openjdk.btrace.extension.ExtensionRegistry;\nimport org.openjdk.btrace.instr.BTraceProbe;\nimport org.openjdk.btrace.instr.BTraceProbeFactory;\nimport org.openjdk.btrace.instr.BTraceProbePersisted;\nimport org.openjdk.btrace.instr.BTraceTransformer;\nimport org.openjdk.btrace.instr.ClassCache;\nimport org.openjdk.btrace.instr.ClassFilter;\nimport org.openjdk.btrace.instr.ClassInfo;\nimport org.openjdk.btrace.instr.InstrumentUtils;\nimport org.openjdk.btrace.instr.Instrumentor;\nimport org.openjdk.btrace.instr.MethodTrackingContext;\nimport org.openjdk.btrace.runtime.BTraceRuntimeAccess;\nimport org.openjdk.btrace.runtime.BTraceRuntimes;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.lang.annotation.Annotation;\nimport java.lang.instrument.Instrumentation;\nimport java.lang.instrument.UnmodifiableClassException;\nimport java.lang.management.ManagementFactory;\nimport java.text.DateFormat;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\n/**\n * Abstract class that represents a BTrace client at the BTrace agent.\n *\n * @author A. Sundararajan\n * @author J. Bachorik (j.bachorik@btrace.io)\n */\nabstract class Client implements CommandListener {\n  private static final Logger log = LoggerFactory.getLogger(Client.class);\n\n  private static final Map<UUID, Client> CLIENTS = new ConcurrentHashMap<>();\n  private static final Map<String, PrintWriter> WRITER_MAP = new HashMap<>();\n  private static final Pattern SYSPROP_PTN = Pattern.compile(\"\\\\$\\\\{(.+?)}\");\n\n  static {\n    ClassFilter.class.getClassLoader();\n    InstrumentUtils.class.getClassLoader();\n    Instrumentor.class.getClassLoader();\n    ClassReader.class.getClassLoader();\n    ClassWriter.class.getClassLoader();\n    Annotation.class.getClassLoader();\n    MethodTrackingContext.class.getClassLoader();\n    ClassCache.class.getClassLoader();\n    ClassInfo.class.getClassLoader();\n  }\n\n  private final Instrumentation inst;\n  final SharedSettings settings;\n  final ArgsMap argsMap;\n  private final BTraceTransformer transformer;\n  volatile PrintWriter out;\n  private volatile BTraceRuntime.Impl runtime;\n  private volatile String outputName;\n  private BTraceProbe probe;\n  private Timer flusher;\n  private volatile boolean initialized = false;\n  private volatile boolean shuttingDown = false;\n  final UUID id = UUID.randomUUID();\n\n  Client(ClientContext ctx) {\n    this(ctx.getInstr(), ctx.getArguments(), ctx.getSettings(), ctx.getTransformer());\n  }\n\n  private Client(Instrumentation inst, ArgsMap argsMap, SharedSettings s, BTraceTransformer t) {\n    this.inst = inst;\n    this.argsMap = argsMap;\n    settings = s != null ? s : SharedSettings.GLOBAL;\n    transformer = t;\n\n    setupWriter();\n    CLIENTS.put(id, this);\n  }\n\n  private static String pid() {\n    String pName = ManagementFactory.getRuntimeMXBean().getName();\n    if (pName != null && pName.length() > 0) {\n      String[] parts = pName.split(\"@\");\n      if (parts.length == 2) {\n        return parts[0];\n      }\n    }\n\n    return \"-1\";\n  }\n\n  protected final void initialize() {\n    initialized = true;\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  private final void setupWriter() {\n    String outputFile = settings.getOutputFile();\n    if (outputFile == null || outputFile.equals(\"::null\") || outputFile.equals(\"/dev/null\")) return;\n\n    if (!outputFile.equals(\"::stdout\")) {\n      String outputDir = settings.getScriptDir();\n      String output = (outputDir != null ? outputDir + File.separator : \"\") + outputFile;\n      outputFile = templateOutputFileName(output);\n      log.info(\"Redirecting output to {}\", outputFile);\n    }\n    out = WRITER_MAP.get(outputFile);\n    if (out == null) {\n      if (outputFile.equals(\"::stdout\")) {\n        out = new PrintWriter(System.out);\n      } else {\n        if (settings.getFileRollMilliseconds() > 0) {\n          out =\n              new PrintWriter(\n                  new BufferedWriter(\n                      TraceOutputWriter.rollingFileWriter(new File(outputFile), settings)));\n        } else {\n          out =\n              new PrintWriter(\n                  new BufferedWriter(TraceOutputWriter.fileWriter(new File(outputFile))));\n        }\n      }\n      WRITER_MAP.put(outputFile, out);\n      out.append(\"### BTrace Log: \")\n          .append(DateFormat.getInstance().format(new Date()))\n          .append(\"\\n\\n\");\n      startFlusher();\n    }\n    outputName = outputFile;\n  }\n\n  private void startFlusher() {\n    int flushInterval;\n    String flushIntervalStr = System.getProperty(\"org.openjdk.btrace.FileClient.flush\");\n    if (flushIntervalStr == null) {\n      flushIntervalStr = System.getProperty(\"com.sun.btrace.FileClient.flush\", \"5\");\n    }\n    try {\n      flushInterval = Integer.parseInt(flushIntervalStr);\n    } catch (NumberFormatException e) {\n      flushInterval = 5; // default\n    }\n\n    int flushSec = flushInterval;\n    if (flushSec > -1) {\n      flusher = new Timer(\"BTrace FileClient Flusher\", true);\n      flusher.scheduleAtFixedRate(\n          new TimerTask() {\n            @Override\n            public void run() {\n              try {\n                if (out != null) {\n                  boolean entered = BTraceRuntime.enter();\n                  try {\n                    out.flush();\n                  } finally {\n                    if (entered) {\n                      BTraceRuntime.leave();\n                    }\n                  }\n                }\n              } catch (Throwable t) {\n                log.error(\"Error during periodic flush\", t);\n              }\n            }\n          },\n          flushSec,\n          flushSec);\n    } else {\n      flusher = null;\n    }\n  }\n\n  private String templateOutputFileName(String fName) {\n    if (fName != null) {\n      boolean dflt = fName.contains(\"[default]\");\n      String agentName = System.getProperty(\"btrace.agent\", \"default\");\n      String clientName = settings.getClientName();\n      fName =\n          fName\n              .replace(\"${client}\", clientName != null ? clientName : \"\")\n              .replace(\"${ts}\", String.valueOf(System.currentTimeMillis()))\n              .replace(\"${pid}\", pid())\n              .replace(\"${agent}\", agentName != null ? \".\" + agentName : \"\")\n              .replace(\"[default]\", \"\");\n\n      fName = replaceSysProps(fName);\n      if (dflt && log.isDebugEnabled()) {\n        log.debug(\"scriptOutputFile not specified. defaulting to {}\", fName);\n      }\n    }\n    return fName;\n  }\n\n  private String replaceSysProps(String str) {\n    int replaced = 0;\n    do {\n      StringBuffer sb = new StringBuffer();\n      replaced = replaceSysProps(str, sb);\n      str = sb.toString();\n    } while (replaced > 0);\n    return str;\n  }\n\n  private int replaceSysProps(String str, StringBuffer sb) {\n    int cnt = 0;\n    Matcher m = SYSPROP_PTN.matcher(str);\n    while (m.find()) {\n      String key = m.group(1);\n      String val = System.getProperty(key);\n      if (val != null) {\n        cnt++;\n        m.appendReplacement(sb, val);\n      } else {\n        m.appendReplacement(sb, m.group(0));\n      }\n    }\n    m.appendTail(sb);\n    return cnt;\n  }\n\n  static Collection<String> listProbes() {\n    List<String> probes = new ArrayList<>(CLIENTS.size());\n    for (Client client : CLIENTS.values()) {\n      if (client instanceof RemoteClient) {\n        if (((RemoteClient) client).isDisconnected()) {\n          probes.add(client.id + \" [\" + client.getClassName() + \"]\");\n        }\n      }\n    }\n    return probes;\n  }\n\n  synchronized void onExit(int exitCode) {\n    if (!shuttingDown) {\n      shuttingDown = true;\n      if (out != null) {\n        out.flush();\n      }\n\n      BTraceRuntime.leave();\n      try {\n        log.debug(\"onExit:\");\n        log.debug(\"cleaning up transformers\");\n        cleanupTransformers();\n        log.debug(\"removing instrumentation\");\n        retransformLoaded();\n        log.debug(\"closing all I/O\");\n        // Send EXIT command to notify remote client before closing\n        sendCommand(new ExitCommand(exitCode));\n        Thread.sleep(300);\n        try {\n          closeAll();\n        } catch (IOException e) {\n          // ignore IOException when closing\n        }\n        log.debug(\"done\");\n      } catch (Throwable th) {\n        // ExitException is expected here\n        if (!th.getClass().getName().equals(\"ExitException\")) {\n          log.debug(\"Failed to gracefully exit BTrace probe\", th);\n          BTraceRuntime.handleException(th);\n        }\n      } finally {\n        runtime.shutdownCmdLine();\n        CLIENTS.remove(id);\n      }\n    }\n  }\n\n  final synchronized Class<?> loadClass(InstrumentCommand instr) throws IOException {\n    ArgsMap args = instr.getArguments();\n    byte[] btraceCode = instr.getCode();\n    try {\n      probe = load(btraceCode, ArgsMap.merge(argsMap, args));\n      if (probe == null) {\n        log.debug(\"Failed to load BTrace probe code\");\n        return null;\n      }\n\n      if (!settings.isTrusted()) {\n        probe.checkVerified();\n      }\n\n      // Check probe's required permissions against effective permissions\n      Set<Permission> required = probe.getRequiredPermissions();\n      if (!required.isEmpty()) {\n        PermissionSet effective = settings.getEffectivePermissions();\n        Set<Permission> missing =\n            required.stream().filter(p -> !effective.has(p)).collect(Collectors.toSet());\n        if (!missing.isEmpty()) {\n          throw new SecurityException(formatPermissionError(missing));\n        }\n      }\n\n      // Validate that all injected service types are declared by available extensions\n      validateDeclaredServices(probe);\n    } catch (Throwable th) {\n      log.debug(\"Failed to load BTrace probe code\", th);\n      errorExit(th);\n      return null;\n    }\n    if (log.isDebugEnabled()) {\n      log.debug(\"creating BTraceRuntime instance for {}\", probe.getClassName());\n    }\n    runtime = BTraceRuntimes.getRuntime(probe.getClassName(), args, this, inst);\n    Runtime.getRuntime()\n        .addShutdownHook(\n            new Thread(\n                () -> {\n                  if (runtime != null) {\n                    runtime.handleExit(0);\n                  }\n                }));\n    if (probe.isClassRenamed()) {\n      if (log.isDebugEnabled()) {\n        log.debug(\"class renamed to {}\", probe.getClassName());\n      }\n      sendCommand(new RenameCommand(probe.getClassName()));\n    }\n    if (log.isDebugEnabled()) {\n      log.debug(\"created BTraceRuntime instance for {}\", probe.getClassName());\n      log.debug(\"sending Okay command\");\n    }\n\n    sendCommand(new StatusCommand());\n\n    // Warn about failed extensions\n    Map<String, String> failed = ExtensionRegistry.getFailedExtensions();\n    if (!failed.isEmpty()) {\n      StringBuilder warning = new StringBuilder();\n      warning.append(\"[BTRACE WARN] \").append(failed.size())\n             .append(\" extension(s) failed to load:\\n\");\n      for (Map.Entry<String, String> entry : failed.entrySet()) {\n        String simpleName = entry.getKey().substring(entry.getKey().lastIndexOf('.') + 1);\n        warning.append(\"  - \").append(simpleName)\n               .append(\": \").append(entry.getValue()).append(\"\\n\");\n      }\n      warning.append(\"Use 'btrace -le <PID>' for details.\\n\");\n      sendCommand(new MessageCommand(warning.toString()));\n    }\n\n    // Expose extension-declared permissions for integration visibility\n    // Print extension permissions only when explicitly requested (debug or system property)\n    if (settings.isDebug() || Boolean.getBoolean(\"btrace.list.extension.permissions\")) {\n      try {\n        ExtensionLoader loader = Main.getExtensionLoader();\n        if (loader != null) {\n          StringBuilder info = new StringBuilder();\n          info.append(\"[BTRACE INFO] Extensions and declared permissions:\\n\");\n          for (ExtensionDescriptorDTO ext : loader.getAvailableExtensions()) {\n            PermissionSet perms = ext.getRequiredPermissions();\n            String pStr = perms != null && !perms.isEmpty() ? perms.toString() : \"[]\";\n            info.append(\"  - \").append(ext.getId()).append(\": \").append(pStr).append(\"\\n\");\n          }\n          sendCommand(new MessageCommand(info.toString()));\n        }\n      } catch (Throwable t) {\n        // ignore, informational only\n      }\n    }\n\n    boolean entered = false;\n    try {\n      entered = BTraceRuntimeAccess.enter((BTraceRuntimeBridge) runtime);\n      return probe.register(runtime, transformer);\n    } catch (Throwable th) {\n      log.debug(\"Failed to load BTrace probe\", th);\n      errorExit(th);\n      return null;\n    } finally {\n      if (entered) {\n        BTraceRuntime.leave();\n      }\n    }\n  }\n\n  /**\n   * Validates that all {@code @Injected} service field types used by the given probe are\n   * declared by some available extension. This runs in the agent's runtime where the actual\n   * classloader and JPMS module layer apply.\n   *\n   * Why reflection here (vs. pure ASM):\n   * - Classloader identity: Ensures types are checked against the agent's classes loaded by the\n   *   correct loader. Name-only checks in ASM cannot detect split-brain issues (same FQN, different\n   *   loader/JAR) that would later cause ClassCastException.\n   * - JPMS access rules: Surfaces missing exports/opens and other module access constraints that\n   *   cannot be proven by static bytecode analysis.\n   * - Linkage/loadability: Fails fast if a referenced type is not actually resolvable on the\n   *   agent's runtime path (NoClassDefFoundError/missing transitive dependencies).\n   * - Assignability truth: Verifies that the service type corresponds to something an extension\n   *   actually declares in its manifest, avoiding false positives from shaded or version-skewed\n   *   classes.\n   *\n   * Implementation notes:\n   * - We use reflection only to access the probe's internal service field map (to avoid a direct\n   *   compile-time dependency on the probe's delegate type) and to keep the agent/probe boundary\n   *   clean. We do not instantiate user classes or trigger class initializers.\n   * - This check complements compile-time and bytecode-time validation (ASM-based) which enforce\n   *   structural rules without loading classes. Reflection here provides the necessary runtime\n   *   assurance in the actual environment where the agent will operate.\n   */\n  private void validateDeclaredServices(BTraceProbe probe) throws IOException {\n    if (!(probe instanceof BTraceProbePersisted)) {\n      return;\n    }\n    ExtensionLoader loader = Main.getExtensionLoader();\n    if (loader == null) {\n      return;\n    }\n    // Reflectively access serviceFields() from the delegate to get injected service types\n    try {\n      java.lang.reflect.Field delF = BTraceProbePersisted.class.getDeclaredField(\"delegate\");\n      delF.setAccessible(true);\n      Object delegate = delF.get(probe);\n      java.lang.reflect.Method svcM = delegate.getClass().getDeclaredMethod(\"serviceFields\");\n      svcM.setAccessible(true);\n      @SuppressWarnings(\"unchecked\")\n      Map<String, String> svcMap = (Map<String, String>) svcM.invoke(delegate);\n      if (svcMap != null) {\n        for (String internalName : svcMap.values()) {\n          String fqcn = internalName.replace('/', '.');\n          if (loader.findExtensionForService(fqcn) == null) {\n            throw new IOException(\n                \"Injected service type not declared by any extension: \" + fqcn);\n          }\n        }\n      }\n    } catch (ReflectiveOperationException e) {\n      log.debug(\"Unable to inspect injected services for validation\", e);\n    }\n  }\n\n  protected void closeAll() throws IOException {\n    if (flusher != null) {\n      flusher.cancel();\n    }\n    if (out != null) {\n      out.close();\n    }\n    WRITER_MAP.remove(outputName);\n  }\n\n  private void errorExit(Throwable th) throws IOException {\n    log.debug(\"sending error command\");\n    sendCommand(new ErrorCommand(th));\n    log.debug(\"sending exit command\");\n    sendCommand(new ExitCommand(1));\n    closeAll();\n  }\n\n  private void cleanupTransformers() {\n    if (probe != null) {\n      String probeName = probe.getClassName();\n      probe.unregister();\n      // Drop the registry's strong reference to the BTraceRuntime.Impl created in\n      // initialize() via BTraceRuntimes.getRuntime(probe.getClassName(), ...). Without\n      // this, the registry keeps the Impl (and, transitively, the probe Class<?> and\n      // its per-probe ClassLoader) reachable forever, defeating probe class unloading.\n      // Must use the same key that was used to register — here, the dotted class name.\n      BTraceRuntimes.removeRuntime(probeName);\n    }\n  }\n\n  // package privates below this point\n  final boolean isInitialized() {\n    return initialized;\n  }\n\n  final BTraceRuntime.Impl getRuntime() {\n    return runtime;\n  }\n\n  final String getClassName() {\n    return probe != null ? probe.getClassName() : \"<unknown>\";\n  }\n\n  private final boolean isCandidate(Class<?> c) {\n    String cname = c.getName().replace('.', '/');\n    if (c.isInterface() || c.isPrimitive() || c.isArray()) {\n      return false;\n    }\n    if (ClassFilter.isSensitiveClass(cname)) {\n      return false;\n    } else {\n      return probe.willInstrument(c);\n    }\n  }\n\n  private final void startRetransformClasses(int numClasses) {\n    sendCommand(new RetransformationStartNotification(numClasses));\n    if (log.isDebugEnabled()) {\n      log.debug(\"calling retransformClasses ({} classes to be retransformed)\", numClasses);\n    }\n  }\n\n  final void endRetransformClasses() {\n    sendCommand(new StatusCommand());\n    log.debug(\"finished retransformClasses\");\n  }\n\n  // Internals only below this point\n  private BTraceProbe load(byte[] buf, ArgsMap args) {\n    BTraceProbeFactory f = new BTraceProbeFactory(settings);\n    log.debug(\"loading BTrace class\");\n    BTraceProbe cn = f.createProbe(buf, args);\n\n    if (cn != null) {\n      if (cn.isVerified()) {\n        if (log.isDebugEnabled()) {\n          log.debug(\"loaded '{}' successfully\", cn.getClassName());\n        }\n      } else {\n        if (log.isDebugEnabled()) {\n          log.debug(\"{} failed verification\", cn.getClassName());\n        }\n        return null;\n      }\n    }\n    return BTraceProbePersisted.from(cn);\n  }\n\n  boolean retransformLoaded() throws UnmodifiableClassException {\n    if (runtime == null) {\n      return false;\n    }\n    if (probe.isTransforming() && settings.isRetransformStartup()) {\n      ArrayList<Class<?>> list = new ArrayList<>();\n      log.debug(\"retransforming loaded classes\");\n      log.debug(\"filtering loaded classes\");\n      ClassCache cc = ClassCache.getInstance();\n      for (Class<?> c : inst.getAllLoadedClasses()) {\n        if (c != null) {\n          if (inst.isModifiableClass(c) && isCandidate(c)) {\n            if (log.isDebugEnabled()) {\n              log.debug(\"candidate {} added\", c);\n            }\n            list.add(c);\n          }\n        }\n      }\n      list.trimToSize();\n      int size = list.size();\n      if (size > 0) {\n        Class<?>[] classes = new Class[size];\n        list.toArray(classes);\n        startRetransformClasses(size);\n        if (log.isDebugEnabled()) {\n          for (Class<?> c : classes) {\n            try {\n              log.debug(\"Attempting to retransform class: {}\", c.getName());\n              inst.retransformClasses(c);\n            } catch (ClassFormatError | VerifyError e) {\n              // Avoid printing full stack traces in debug to keep target stderr clean\n              log.debug(\"Class '{}' verification failed: {}\", c.getName(), e.toString());\n              sendCommand(\n                  new MessageCommand(\n                      \"[BTRACE WARN] Class verification failed: \"\n                          + c.getName()\n                          + \" (\"\n                          + e.getMessage()\n                          + \")\"));\n            }\n          }\n        } else {\n          try {\n            inst.retransformClasses(classes);\n          } catch (ClassFormatError | VerifyError e) {\n            /*\n             * If the en-block retransformation fails because of verification retry classes one-by-one.\n             * Otherwise all classes are rolled back to the original state and no instrumentation\n             * is applied.\n             */\n            for (Class<?> c : classes) {\n              try {\n                inst.retransformClasses(c);\n              } catch (ClassFormatError | VerifyError e1) {\n                // Avoid printing full stack traces in debug to keep target stderr clean\n                log.debug(\"Class '{}' verification failed: {}\", c.getName(), e1.toString());\n                sendCommand(\n                    new MessageCommand(\n                        \"[BTRACE WARN] Class verification failed: \"\n                            + c.getName()\n                            + \" (\"\n                            + e1.getMessage()\n                            + \")\"));\n              }\n            }\n          }\n        }\n      }\n    }\n    return true;\n  }\n\n  protected void sendCommand(Command command) {\n    if (runtime == null) {\n      log.warn(\"Cannot send command {}, runtime not initialized\", command.getClass().getSimpleName());\n      return;\n    }\n    runtime.sendCommand(command);\n  }\n\n  static Client findClient(String uuid) {\n    try {\n      UUID id = UUID.fromString(uuid);\n      return CLIENTS.get(id);\n    } catch (IllegalArgumentException e) {\n      return null;\n    }\n  }\n\n  @Override\n  public String toString() {\n    return \"BTrace Client: \" + id + \"[\" + probe.getClassName() + \"]\";\n  }\n\n  private static String formatPermissionError(Set<Permission> missing) {\n    StringBuilder sb = new StringBuilder();\n    sb.append(\"Probe requires permissions that are not granted:\\n\\n\");\n    for (Permission p : missing) {\n      sb.append(\"  - \").append(p.name()).append(\"\\n\");\n      sb.append(\"    \").append(p.getRiskDescription()).append(\"\\n\");\n    }\n    sb.append(\"\\nTo allow these permissions, use:\\n\");\n    sb.append(\"  --grant=\")\n        .append(missing.stream().map(Permission::name).collect(Collectors.joining(\",\")))\n        .append(\"\\n\");\n    sb.append(\"\\nOr use --grantAll=true to allow all permissions (not recommended).\\n\");\n    return sb.toString();\n  }\n}\n"
  },
  {
    "path": "btrace-agent/src/main/java/org/openjdk/btrace/agent/ClientContext.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.agent;\n\nimport java.lang.instrument.Instrumentation;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.instr.BTraceTransformer;\n\n/**\n * Client-context data class\n *\n * @author Jaroslav Bachorik\n */\nclass ClientContext {\n  private final Instrumentation instr;\n  private final BTraceTransformer transformer;\n  private final ArgsMap args;\n  private final SharedSettings settings;\n\n  ClientContext(\n      Instrumentation instr, BTraceTransformer transformer, ArgsMap args, SharedSettings settings) {\n    this.instr = instr;\n    this.transformer = transformer;\n    this.args = args;\n    this.settings = settings;\n  }\n\n  Instrumentation getInstr() {\n    return instr;\n  }\n\n  BTraceTransformer getTransformer() {\n    return transformer;\n  }\n\n  SharedSettings getSettings() {\n    return settings;\n  }\n\n  ArgsMap getArguments() {\n    return args;\n  }\n}\n"
  },
  {
    "path": "btrace-agent/src/main/java/org/openjdk/btrace/agent/FileClient.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.agent;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLDecoder;\nimport java.security.CodeSigner;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.ExitCommand;\nimport org.openjdk.btrace.core.comm.InstrumentCommand;\nimport org.openjdk.btrace.core.comm.PrintableCommand;\nimport org.openjdk.btrace.instr.Constants;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Represents a local client communicated by trace file. The trace script is specified as a File of\n * a .class file or a byte array containing bytecode of the trace script.\n *\n * @author A. Sundararajan\n * @author J.Bachorik\n */\nclass FileClient extends Client {\n  private static final Logger log = LoggerFactory.getLogger(FileClient.class);\n\n  private final AtomicBoolean noOutputNotified = new AtomicBoolean(false);\n\n  private boolean canLoadPack = true;\n\n  FileClient(ClientContext ctx, File scriptFile) throws IOException {\n    super(ctx);\n    if (!init(readScript(scriptFile))) {\n      log.warn(\"Unable to load BTrace script {}\", scriptFile);\n    }\n  }\n\n  private static byte[] readAll(InputStream is, long size) throws IOException {\n    if (is == null) throw new NullPointerException();\n\n    byte[] buf = new byte[size != -1 ? Math.min((int) size, 512 * 1024 * 1024) : 8192];\n    int bufsize = buf.length;\n    int off = 0;\n    int read;\n    while ((read = is.read(buf, off, bufsize - off)) > -1) {\n      off += read;\n      if (off >= bufsize) {\n        buf = Arrays.copyOf(buf, bufsize * 2);\n        bufsize = buf.length;\n      }\n    }\n    return Arrays.copyOf(buf, off);\n  }\n\n  private boolean init(byte[] code) throws IOException {\n    InstrumentCommand cmd = new InstrumentCommand(code, argsMap);\n    boolean ret = loadClass(cmd) != null;\n    if (ret) {\n      initialize();\n    }\n    return ret;\n  }\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  public void onCommand(Command cmd) throws IOException {\n    if (log.isDebugEnabled()) {\n      log.debug(\"client {}: got {}\", getClassName(), cmd);\n    }\n    switch (cmd.getType()) {\n      case Command.EXIT:\n        onExit(((ExitCommand) cmd).getExitCode());\n        break;\n      default:\n        if (cmd instanceof PrintableCommand) {\n          if (out == null) {\n            if (noOutputNotified.compareAndSet(false, true)) {\n              log.debug(\"No output stream. DataCommand output is ignored.\");\n            }\n          } else {\n            ((PrintableCommand) cmd).print(out);\n            out.flush();\n          }\n        }\n        break;\n    }\n  }\n\n  private byte[] readScript(File file) throws IOException {\n    String path = file.getPath();\n    if (path.startsWith(Constants.EMBEDDED_BTRACE_SECTION_HEADER)) {\n      return settings.isTrusted() ? loadQuick(path) : loadWithSecurity(path);\n    } else {\n      int size = (int) file.length();\n      try (FileInputStream fis = new FileInputStream(file)) {\n        return readAll(fis, size);\n      }\n    }\n  }\n\n  private byte[] loadQuick(String path) throws IOException {\n    try (InputStream is = ClassLoader.getSystemResourceAsStream(path)) {\n      return readAll(is, -1);\n    }\n  }\n\n  private byte[] loadWithSecurity(String path) throws IOException {\n    URL scriptUrl = ClassLoader.getSystemResource(path);\n    if (scriptUrl.getProtocol().equals(\"jar\")) {\n      String jarPath = scriptUrl.getPath().substring(5, scriptUrl.getPath().indexOf(\"!\"));\n      JarFile jar = new JarFile(URLDecoder.decode(jarPath, \"UTF-8\"));\n      Enumeration<JarEntry> ens = jar.entries();\n\n      while (ens.hasMoreElements()) {\n        JarEntry en = ens.nextElement();\n\n        if (!en.isDirectory()) {\n          if (en.toString().equals(path)) {\n            byte[] data = readAll(jar.getInputStream(en), en.getSize());\n            CodeSigner[] signers = en.getCodeSigners();\n            canLoadPack = signers != null && signers.length != 0;\n            return data;\n          }\n        }\n      }\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "btrace-agent/src/main/java/org/openjdk/btrace/agent/Main.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.agent;\n\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.DebugSupport;\nimport org.openjdk.btrace.core.Messages;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.core.comm.ErrorCommand;\nimport org.openjdk.btrace.core.comm.StatusCommand;\nimport org.openjdk.btrace.core.comm.WireIO;\nimport org.openjdk.btrace.extension.ExtensionLoader;\nimport org.openjdk.btrace.extension.impl.ExtensionBridgeImpl;\nimport org.openjdk.btrace.instr.BTraceProbeFactory;\nimport org.openjdk.btrace.instr.BTraceTransformer;\nimport org.openjdk.btrace.instr.Constants;\nimport org.openjdk.btrace.runtime.BTraceRuntimes;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.instrument.Instrumentation;\nimport java.lang.instrument.UnmodifiableClassException;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.net.URL;\nimport java.nio.file.FileVisitResult;\nimport java.nio.file.FileVisitor;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.StringTokenizer;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.jar.JarFile;\nimport java.util.regex.Pattern;\nimport java.util.zip.ZipFile;\n\nimport static org.openjdk.btrace.core.Args.ALLOW_EXTENSIONS;\nimport static org.openjdk.btrace.core.Args.ALLOW_PRIVILEGED;\nimport static org.openjdk.btrace.core.Args.BOOT_CLASS_PATH;\nimport static org.openjdk.btrace.core.Args.CMD_QUEUE_LIMIT;\nimport static org.openjdk.btrace.core.Args.CONFIG;\nimport static org.openjdk.btrace.core.Args.DEBUG;\nimport static org.openjdk.btrace.core.Args.DENY;\nimport static org.openjdk.btrace.core.Args.DENY_EXTENSIONS;\nimport static org.openjdk.btrace.core.Args.DUMP_CLASSES;\nimport static org.openjdk.btrace.core.Args.DUMP_DIR;\nimport static org.openjdk.btrace.core.Args.FILE_ROLL_MAX_ROLLS;\nimport static org.openjdk.btrace.core.Args.FILE_ROLL_MILLISECONDS;\nimport static org.openjdk.btrace.core.Args.GRANT;\nimport static org.openjdk.btrace.core.Args.GRANT_ALL;\nimport static org.openjdk.btrace.core.Args.HELP;\nimport static org.openjdk.btrace.core.Args.LIBS;\nimport static org.openjdk.btrace.core.Args.NO_SERVER;\nimport static org.openjdk.btrace.core.Args.PORT;\nimport static org.openjdk.btrace.core.Args.PROBE_DESC_PATH;\nimport static org.openjdk.btrace.core.Args.SCRIPT;\nimport static org.openjdk.btrace.core.Args.SCRIPT_DIR;\nimport static org.openjdk.btrace.core.Args.SCRIPT_OUTPUT_DIR;\nimport static org.openjdk.btrace.core.Args.SCRIPT_OUTPUT_FILE;\nimport static org.openjdk.btrace.core.Args.STARTUP_RETRANSFORM;\nimport static org.openjdk.btrace.core.Args.STATSD;\nimport static org.openjdk.btrace.core.Args.STDOUT;\nimport static org.openjdk.btrace.core.Args.SYSTEM_CLASS_PATH;\nimport static org.openjdk.btrace.core.Args.TRACK_RETRANSFORMS;\nimport static org.openjdk.btrace.core.Args.TRUSTED;\n\n/**\n * This is the main class for BTrace java.lang.instrument agent.\n *\n * @author A. Sundararajan\n * @author Joachim Skeie (rolling output)\n */\n@SuppressWarnings(\"RedundantThrows\")\npublic final class Main {\n  public static final int BTRACE_DEFAULT_PORT = 2020;\n  private static final boolean AGENT_DEBUG = Boolean.getBoolean(\"btrace.agent.debug\");\n  private static final Pattern KV_PATTERN = Pattern.compile(\",\");\n  private static final SharedSettings settings = SharedSettings.GLOBAL;\n  private static final BTraceTransformer transformer =\n      new BTraceTransformer(new DebugSupport(settings));\n  // #BTRACE-42: Non-daemon thread prevents traced application from exiting\n  private static final ThreadFactory qProcessorThreadFactory =\n      r -> {\n        Thread result = new Thread(r, \"BTrace Command Queue Processor\");\n        result.setDaemon(true);\n        return result;\n      };\n  private static final ExecutorService serializedExecutor =\n      Executors.newSingleThreadExecutor(qProcessorThreadFactory);\n  private static final long ts = System.nanoTime();\n  private static volatile ArgsMap argMap;\n  private static volatile Instrumentation inst;\n  private static volatile Long fileRollMilliseconds;\n  private static volatile ExtensionLoader extensionLoader;\n  private static volatile boolean serverRunning = true;\n  private static ServerSocket serverSocket;\n\n  private static final Logger log = LoggerFactory.getLogger(Main.class);\n\n  public static void premain(String args, Instrumentation inst) {\n    main(args, inst);\n  }\n\n  public static void agentmain(String args, Instrumentation inst) {\n    main(args, inst);\n  }\n\n  private static synchronized void main(String args, Instrumentation inst) {\n    if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Initialization started\");\n    if (Main.inst != null) {\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Agent already initialized, skipping\");\n      return;\n    } else {\n      Main.inst = inst;\n    }\n\n    try {\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Loading arguments\");\n      loadArgs(args);\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Arguments loaded\");\n      boolean isDebug = Boolean.parseBoolean(argMap.get(DEBUG));\n      // set the debug level based on cmdline config\n      settings.setDebug(isDebug);\n      DebugSupport.initLoggers(isDebug, log);\n\n      // Load defaults from file-based permission policy first\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Loading permission policy\");\n      org.openjdk.btrace.extension.PermissionPolicy.get().loadFromDefaults();\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Permission policy loaded\");\n      // Then parse and apply agent args (which override file policy)\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Parsing arguments\");\n      parseArgs();\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Arguments parsed\");\n      // settings are all built-up; set the logging system properties accordingly\n      DebugSupport.initLoggers(settings.isDebug(), log);\n\n      String tmp = argMap.get(NO_SERVER);\n      // noServer is defaulting to true if startup scripts are defined\n      boolean noServer = tmp != null ? Boolean.parseBoolean(tmp) : hasScripts();\n      Thread agentThread = null;\n      if (noServer) {\n        log.debug(\"noServer is true, server not started\");\n      } else {\n        agentThread =\n            new Thread(\n                () -> {\n                  BTraceRuntime.enter();\n                  try {\n                    startServer();\n                  } finally {\n                    BTraceRuntime.leave();\n                  }\n                });\n      }\n      // set the fall-back instrumentation object to BTraceRuntime\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Setting up runtime\");\n      BTraceRuntime.instrumentation = inst;\n      // force back-registration of BTraceRuntimeImpl in BTraceRuntime\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Initializing BTraceRuntimes\");\n      BTraceRuntimes.getDefault();\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] BTraceRuntimes initialized\");\n      // ensure runtime accessor is registered\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Registering runtime accessor\");\n      BTraceRuntimes.ensureAccessorRegistered();\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Runtime accessor registered\");\n      // init BTraceRuntime\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Initializing unsafe\");\n      BTraceRuntime.initUnsafe();\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Unsafe initialized\");\n      // initialize extension system\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Initializing extensions\");\n      initExtensions();\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Extensions initialized\");\n      if (agentThread != null) {\n        BTraceRuntime.enter();\n        try {\n          agentThread.setDaemon(true);\n          log.debug(\"starting agent thread\");\n\n          agentThread.start();\n        } finally {\n          BTraceRuntime.leave();\n        }\n      }\n\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Adding class transformer\");\n      log.debug(\"Adding class transformer\");\n      inst.addTransformer(transformer, true);\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Transformer added\");\n      try {\n        // the MethodHandleNatives must be instrumented to track start-end of indy linking to avoid deadlocking\n        if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Instrumenting MethodHandleNatives\");\n        Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(\"java.lang.invoke.MethodHandleNatives\");\n        inst.retransformClasses(clz);\n        if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] MethodHandleNatives instrumented\");\n      } catch (Throwable t) {\n        if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Failed to instrument MethodHandleNatives: \" + t.getMessage());\n        log.debug(\"Failed to instrument MethodHandleNatives\", t);\n      }\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Starting scripts\");\n      int startedScripts = startScripts();\n      if (AGENT_DEBUG) System.err.println(\"[BTrace Agent] Initialization complete, \" + startedScripts + \" scripts started\");\n    } catch (Throwable t) {\n      // FATAL errors should always be printed\n      System.err.println(\"[BTrace Agent] FATAL: Initialization failed: \" + t.getClass().getName() + \": \" + t.getMessage());\n      t.printStackTrace(System.err);\n      log.error(\"Failed to initialize BTrace agent\", t);\n      throw new RuntimeException(\"BTrace agent initialization failed\", t);\n    } finally {\n      log.debug(\"Agent init took: {}\", (System.nanoTime() - ts) + \"ns\");\n    }\n  }\n\n  private static boolean hasScripts() {\n    return argMap.containsKey(SCRIPT) || argMap.containsKey(SCRIPT_DIR);\n  }\n\n  private static final class LogValue {\n    final String logLine;\n    final Throwable throwable;\n\n    public LogValue(String logLine, Throwable throwable) {\n      this.logLine = logLine;\n      this.throwable = throwable;\n    }\n  }\n\n  private static void loadDefaultArguments(String config) {\n    try {\n      String propTarget = Constants.EMBEDDED_BTRACE_SECTION_HEADER + \"agent.properties\";\n      InputStream is = ClassLoader.getSystemResourceAsStream(propTarget);\n      if (is != null) {\n        Properties ps = new Properties();\n        ps.load(is);\n        StringBuilder logMsg = new StringBuilder();\n        for (Map.Entry<Object, Object> entry : ps.entrySet()) {\n          String keyConfig = \"\";\n          String argKey = (String) entry.getKey();\n          int configPos = argKey.lastIndexOf('#');\n          if (configPos > -1) {\n            keyConfig = argKey.substring(0, configPos);\n            argKey = argKey.substring(configPos + 1);\n          }\n          if (config == null || keyConfig.isEmpty() || config.equals(keyConfig)) {\n            String argVal = (String) entry.getValue();\n            switch (argKey) {\n              case SCRIPT:\n                {\n                  // special treatment for the 'script' parameter\n                  boolean replace = false;\n                  String scriptVal = argVal;\n                  if (scriptVal.startsWith(\"!\")) {\n                    scriptVal = scriptVal.substring(1);\n                    replace = true;\n                  } else {\n                    String oldVal = argMap.get(argKey);\n                    if (oldVal != null && !oldVal.isEmpty()) {\n                      scriptVal = oldVal + \":\" + scriptVal;\n                    } else {\n                      replace = true;\n                    }\n                  }\n                  if (replace) {\n                    logMsg\n                        .append(\"setting default agent argument '\")\n                        .append(argKey)\n                        .append(\"' to '\")\n                        .append(scriptVal)\n                        .append(\"'\\n\");\n                  } else {\n                    logMsg\n                        .append(\"augmenting default agent argument '\")\n                        .append(argKey)\n                        .append(\"':'\")\n                        .append(argMap.get(argKey))\n                        .append(\"' with '\")\n                        .append(argVal)\n                        .append(\"'\\n\");\n                  }\n\n                  argMap.put(argKey, scriptVal);\n                  break;\n                }\n              case SYSTEM_CLASS_PATH: // fall through\n              case BOOT_CLASS_PATH: // fall through\n              case CONFIG:\n                {\n                  logMsg.append(\"argument '\").append(argKey).append(\"' is not overridable\\n\");\n                  break;\n                }\n              default:\n                {\n                  if (!argMap.containsKey(argKey)) {\n                    logMsg\n                        .append(\"applying default agent argument '\")\n                        .append(argKey)\n                        .append(\"'='\")\n                        .append(argVal)\n                        .append(\"'\\n\");\n                    argMap.put(argKey, argVal);\n                  }\n                }\n            }\n          }\n        }\n        DebugSupport.initLoggers(Boolean.parseBoolean(argMap.get(DEBUG)), log);\n        if (log.isDebugEnabled()) {\n          log.debug(logMsg.toString());\n        }\n      }\n    } catch (IOException e) {\n      if (log.isDebugEnabled()) {\n        log.debug(e.toString(), e);\n      }\n    }\n  }\n\n  /**\n   * Initialize the extension system by discovering and loading extensions\n   * from configured extension directories.\n   */\n  private static void initExtensions() {\n    try {\n      log.info(\"Initializing BTrace extension system\");\n\n      // Determine BTRACE_HOME from agent JAR location\n      String btraceHome = getBTraceHome();\n      if (log.isDebugEnabled()) {\n        log.debug(\"BTRACE_HOME={}\", btraceHome);\n      }\n      if (btraceHome == null) {\n        log.warn(\"Could not determine BTRACE_HOME, extensions will not be loaded\");\n        System.err.println(\"[DEBUG] BTRACE_HOME is null, skipping extension initialization\");\n        return;\n      }\n\n      // Initialize extension loader with boot classloader as parent, configuration, and instrumentation\n      ClassLoader bootClassLoader = Main.class.getClassLoader();\n      extensionLoader = ExtensionLoader.initialize(btraceHome, bootClassLoader, inst);\n\n      // Initialize invokedynamic bridge for extensions after loader is ready\n      ExtensionBridgeImpl.initialize(extensionLoader);\n\n    } catch (Exception e) {\n      log.error(\"Failed to initialize extension system: {}\", e.getMessage(), e);\n    }\n  }\n\n  /**\n   * Get BTRACE_HOME directory by locating the agent JAR.\n   *\n   * @return BTRACE_HOME path, or null if not found\n   */\n  private static String getBTraceHome() {\n    try {\n      // Get the agent JAR location\n      String agentPath =\n          Main.class.getProtectionDomain().getCodeSource().getLocation().getPath();\n\n      // Agent is typically at BTRACE_HOME/libs/btrace-agent.jar or BTRACE_HOME/libs/btrace.jar\n      File agentJar = new File(agentPath);\n      String jarName = agentJar.getName();\n      if (agentJar.exists()\n          && (jarName.equals(\"btrace-agent.jar\") || jarName.equals(\"btrace.jar\"))) {\n        File libsDir = agentJar.getParentFile();\n        if (libsDir != null && libsDir.getName().equals(\"libs\")) {\n          File btraceHome = libsDir.getParentFile();\n          if (btraceHome != null) {\n            return btraceHome.getAbsolutePath();\n          }\n        }\n      }\n\n      // Try BTRACE_HOME environment variable\n      String envHome = System.getenv(\"BTRACE_HOME\");\n      if (envHome != null && new File(envHome).exists()) {\n        return envHome;\n      }\n\n    } catch (Exception e) {\n      log.debug(\"Failed to determine BTRACE_HOME: {}\", e.getMessage());\n    }\n\n    return null;\n  }\n\n  /**\n   * Get the extension loader instance.\n   *\n   * @return extension loader, or null if not initialized\n   */\n  public static ExtensionLoader getExtensionLoader() {\n    return extensionLoader;\n  }\n\n  private static int startScripts() {\n    int scriptCount = 0;\n\n    String p = argMap.get(STDOUT);\n    boolean traceToStdOut = p != null && !\"false\".equals(p);\n    if (log.isDebugEnabled()) {\n      log.debug(\"stdout is {}\", traceToStdOut);\n    }\n\n    List<String> scripts = locateScripts(argMap);\n    for (String script : scripts) {\n      if (loadBTraceScript(script, traceToStdOut)) {\n        scriptCount++;\n      }\n    }\n    return scriptCount;\n  }\n\n  static List<String> locateScripts(ArgsMap argsMap) {\n    String script = argsMap.get(SCRIPT);\n    String scriptDir = argsMap.get(SCRIPT_DIR);\n\n    List<String> scripts = new ArrayList<>();\n    if (script != null) {\n      StringTokenizer tokenizer = new StringTokenizer(script, \":\");\n      if (log.isDebugEnabled()) {\n        log.debug(\n            ((tokenizer.countTokens() == 1) ? \"initial script is {}\" : \"initial scripts are {}\"),\n            script);\n      }\n      while (tokenizer.hasMoreTokens()) {\n        scripts.add(tokenizer.nextToken());\n      }\n    }\n    if (scriptDir != null) {\n      File dir = new File(scriptDir);\n      if (dir.isDirectory()) {\n        if (log.isDebugEnabled()) {\n          log.debug(\"found scriptdir: {}\", dir.getAbsolutePath());\n        }\n        File[] files = dir.listFiles();\n        if (files != null) {\n          for (File file : files) {\n            scripts.add(file.getAbsolutePath());\n          }\n        }\n      }\n    }\n    return scripts;\n  }\n\n  private static void usage() {\n    System.out.println(Messages.get(\"btrace.agent.usage\"));\n    System.exit(0);\n  }\n\n  private static void loadArgs(String args) {\n    if (args == null) {\n      args = \"\";\n    }\n    String[] pairs = KV_PATTERN.split(args);\n    argMap = new ArgsMap();\n    for (String s : pairs) {\n      int i = s.indexOf('=');\n      String key, value = \"\";\n      if (i != -1) {\n        key = s.substring(0, i).trim();\n        if (i + 1 < s.length()) {\n          value = s.substring(i + 1).trim();\n        }\n      } else {\n        key = s;\n      }\n      argMap.put(key, value);\n    }\n  }\n\n  private static void parseArgs() {\n    String p = argMap.get(HELP);\n    if (p != null) {\n      usage();\n    }\n\n    String libs = argMap.get(LIBS);\n    String config = argMap.get(CONFIG);\n    processClasspaths(libs);\n    loadDefaultArguments(config);\n\n    p = argMap.get(DEBUG);\n    settings.setDebug(p != null && !\"false\".equals(p));\n    DebugSupport.initLoggers(settings.isDebug(), log);\n\n    log.debug(\"debugMode is {}\", settings.isDebug());\n\n    for (Map.Entry<String, String> e : argMap) {\n      String key = e.getKey();\n      p = e.getValue();\n      switch (key) {\n        case STARTUP_RETRANSFORM:\n          {\n            if (!p.isEmpty()) {\n              settings.setRetransformStartup(Boolean.parseBoolean(p));\n              log.debug(STARTUP_RETRANSFORM + \" is {}\", settings.isRetransformStartup());\n            }\n            break;\n          }\n        case DUMP_DIR:\n          {\n            String dumpClassesVal = argMap.get(DUMP_CLASSES);\n            if (dumpClassesVal != null) {\n              boolean dumpClasses = Boolean.parseBoolean(dumpClassesVal);\n              log.debug(DUMP_CLASSES + \" is {}\", dumpClasses);\n              if (dumpClasses) {\n                String dumpDir = argMap.get(DUMP_DIR);\n                settings.setDumpDir(dumpDir != null ? dumpDir : \".\");\n                if (isDebug()) {\n                  log.debug(DUMP_DIR + \" is {}\", dumpDir);\n                }\n              }\n            }\n            break;\n          }\n        case CMD_QUEUE_LIMIT:\n          {\n            if (!p.isEmpty()) {\n              System.setProperty(BTraceRuntime.CMD_QUEUE_LIMIT_KEY, p);\n              log.debug(CMD_QUEUE_LIMIT + \" provided: {}\", p);\n            }\n\n            break;\n          }\n        case TRACK_RETRANSFORMS:\n          {\n            if (!p.isEmpty()) {\n              settings.setTrackRetransforms(Boolean.parseBoolean(p));\n              if (settings.isTrackRetransforms()) {\n                log.debug(TRACK_RETRANSFORMS + \" is on\");\n              }\n            }\n            break;\n          }\n        case SCRIPT_OUTPUT_FILE:\n          {\n            if (!p.isEmpty()) {\n              settings.setOutputFile(p);\n              log.debug(SCRIPT_OUTPUT_FILE + \" is {}\", p);\n            }\n            break;\n          }\n        case SCRIPT_OUTPUT_DIR:\n          {\n            if (!p.isEmpty()) {\n              settings.setScriptOutputDir(p);\n              log.debug(SCRIPT_OUTPUT_DIR + \" is {}\", p);\n            }\n            break;\n          }\n        case FILE_ROLL_MILLISECONDS:\n          {\n            if (!p.isEmpty()) {\n              Long msParsed = null;\n              try {\n                msParsed = Long.parseLong(p);\n                fileRollMilliseconds = msParsed;\n              } catch (NumberFormatException nfe) {\n                fileRollMilliseconds = null;\n              }\n              if (fileRollMilliseconds != null) {\n                settings.setFileRollMilliseconds(fileRollMilliseconds.intValue());\n                log.debug(FILE_ROLL_MILLISECONDS + \" is {}\", fileRollMilliseconds);\n              }\n            }\n            break;\n          }\n        case FILE_ROLL_MAX_ROLLS:\n          {\n            if (!p.isEmpty()) {\n              Integer rolls = null;\n              try {\n                rolls = Integer.parseInt(p);\n              } catch (NumberFormatException ignored) {\n                // ignore\n              }\n\n              if (rolls != null) {\n                settings.setFileRollMaxRolls(rolls);\n              }\n            }\n            break;\n          }\n        case TRUSTED:\n          {\n            if (!p.isEmpty()) {\n              settings.setTrusted(Boolean.parseBoolean(p));\n              log.debug(\"trustedMode is {}\", settings.isTrusted());\n            }\n            break;\n          }\n        case STATSD:\n          {\n            if (!p.isEmpty()) {\n              String[] parts = p.split(\":\");\n              if (parts.length == 2) {\n                settings.setStatsdHost(parts[0].trim());\n                try {\n                  settings.setStatsdPort(Integer.parseInt(parts[1].trim()));\n                } catch (NumberFormatException ex) {\n                  log.warn(\"Invalid statsd port number: {}\", parts[1]);\n                  // leave the port unconfigured\n                }\n              } else if (parts.length == 1) {\n                settings.setStatsdHost(parts[0].trim());\n              }\n            }\n            break;\n          }\n        case PROBE_DESC_PATH:\n          {\n            settings.setProbeDescPath(!p.isEmpty() ? p : \".\");\n            log.debug(\"probe descriptor path is {}\", settings.getProbeDescPath());\n            break;\n          }\n        case BOOT_CLASS_PATH:\n          {\n            settings.setBootClassPath(!p.isEmpty() ? p : \"\");\n            log.debug(\"probe boot class path is {}\", settings.getBootClassPath());\n            break;\n          }\n        case GRANT:\n          {\n            if (!p.isEmpty()) {\n              settings.setGrantedPermissions(SharedSettings.parsePermissions(p));\n              log.debug(\"granted permissions: {}\", settings.getGrantedPermissions());\n            }\n            break;\n          }\n        case DENY:\n          {\n            if (!p.isEmpty()) {\n              settings.setDeniedPermissions(SharedSettings.parsePermissions(p));\n              log.debug(\"denied permissions: {}\", settings.getDeniedPermissions());\n            }\n            break;\n          }\n        case GRANT_ALL:\n          {\n            if (!p.isEmpty()) {\n              settings.setGrantAll(Boolean.parseBoolean(p));\n              log.debug(\"grantAll: {}\", settings.isGrantAll());\n            }\n            break;\n          }\n        case ALLOW_EXTENSIONS:\n          {\n            if (!p.isEmpty()) {\n              org.openjdk.btrace.extension.PermissionPolicy.get().setAllowExtensionsCsv(p);\n              log.debug(\"allowExtensions: {}\", p);\n            }\n            break;\n          }\n        case DENY_EXTENSIONS:\n          {\n            if (!p.isEmpty()) {\n              org.openjdk.btrace.extension.PermissionPolicy.get().setDenyExtensionsCsv(p);\n              log.debug(\"denyExtensions: {}\", p);\n            }\n            break;\n          }\n        case ALLOW_PRIVILEGED:\n          {\n            if (!p.isEmpty()) {\n              org.openjdk.btrace.extension.PermissionPolicy.get().setAllowPrivileged(Boolean.parseBoolean(p));\n              log.debug(\"allowPrivileged: {}\", p);\n            }\n            break;\n          }\n\n        default:\n          {\n            if (key.startsWith(\"$\")) {\n              String pKey = key.substring(1);\n              System.setProperty(pKey, p);\n              log.debug(\"Setting system property: {}={}\", pKey, p);\n            }\n          }\n      }\n    }\n  }\n\n  private static void processClasspaths(String libs) {\n    // Try to find JAR via Loader.class (unmasked bootstrap class)\n    // Main.class won't work because it's loaded from .classdata\n    String bootPath = null;\n    try {\n      Class<?> loaderClass = Class.forName(\"org.openjdk.btrace.boot.Loader\");\n      URL loaderResource = loaderClass.getResource(\"Loader.class\");\n      if (loaderResource != null) {\n        bootPath = loaderResource.toString();\n        if (bootPath.startsWith(\"jar:file:\")) {\n          // Extract JAR path from jar:file:/path/to/btrace.jar!/org/openjdk/btrace/boot/Loader.class\n          bootPath = bootPath.substring(\"jar:file:\".length());\n          int idx = bootPath.indexOf(\"!\");\n          if (idx > -1) {\n            bootPath = bootPath.substring(0, idx);\n          }\n        }\n      }\n    } catch (ClassNotFoundException e) {\n      // Fall back to Main.class if Loader not found (shouldn't happen)\n      URL agentJar = Main.class.getResource(\"Main.class\");\n      if (agentJar != null) {\n        bootPath = agentJar.toString().replace(\"jar:file:\", \"\");\n        int idx = bootPath.indexOf(\"btrace-agent.jar\");\n        if (idx > -1) {\n          bootPath = bootPath.substring(0, idx) + \"btrace-boot.jar\";\n        }\n      }\n    }\n\n    String bootClassPath = argMap.get(BOOT_CLASS_PATH);\n    if (bootClassPath == null && bootPath != null) {\n      bootClassPath = bootPath;\n    } else if (bootClassPath != null && bootPath != null) {\n      if (\".\".equals(bootClassPath)) {\n        bootClassPath = bootPath;\n      } else {\n        bootClassPath = bootPath + File.pathSeparator + bootClassPath;\n      }\n    }\n    log.debug(\"Bootstrap ClassPath: {}\", bootClassPath);\n\n    StringTokenizer tokenizer = new StringTokenizer(bootClassPath, File.pathSeparator);\n    try {\n      while (tokenizer.hasMoreTokens()) {\n        String path = tokenizer.nextToken();\n        File f = new File(path);\n        if (!f.exists()) {\n          log.debug(\"BTrace bootstrap classpath resource [{}] does not exist\", path);\n        } else {\n          if (f.isFile() && f.getName().toLowerCase().endsWith(\".jar\")) {\n            JarFile jf = asJarFile(f);\n            log.debug(\"Adding jar: {}\", jf);\n            inst.appendToBootstrapClassLoaderSearch(jf);\n          } else {\n            log.debug(\"ignoring boot classpath element '{}' - only jar files allowed\", path);\n          }\n        }\n      }\n    } catch (IOException ex) {\n      log.debug(\"adding to boot classpath failed!\", ex);\n      return;\n    }\n\n    String systemClassPath = argMap.get(SYSTEM_CLASS_PATH);\n    if (systemClassPath != null) {\n      log.debug(\"System ClassPath: {}\", systemClassPath);\n      tokenizer = new StringTokenizer(systemClassPath, File.pathSeparator);\n      try {\n        while (tokenizer.hasMoreTokens()) {\n          String path = tokenizer.nextToken();\n          File f = new File(path);\n          if (!f.exists()) {\n            log.debug(\"BTrace system classpath resource [{}] does not exist.\", path);\n          } else {\n            if (f.isFile() && f.getName().toLowerCase().endsWith(\".jar\")) {\n              JarFile jf = asJarFile(f);\n              inst.appendToSystemClassLoaderSearch(jf);\n            } else {\n              log.debug(\"ignoring system classpath element '{}' - only jar files allowed\", path);\n            }\n          }\n        }\n      } catch (IOException ex) {\n        log.debug(\"adding to boot classpath failed!\", ex);\n        return;\n      }\n    }\n\n    addPreconfLibs(libs);\n  }\n\n  @SuppressWarnings(\"JavaReflectionMemberAccess\")\n  private static JarFile asJarFile(File path) throws IOException {\n    try {\n      Class.forName(\"java.lang.Module\"); // bail out early if on pre Java 9 version\n      Class<Runtime> rtClass = Runtime.class;\n      Method m = rtClass.getMethod(\"version\");\n      Object version = m.invoke(null);\n      // JPMS enabled version of JarFile has different constructor signature\n      return JarFile.class\n          .getConstructor(File.class, boolean.class, int.class, version.getClass())\n          .newInstance(path, true, ZipFile.OPEN_READ, version);\n    } catch (ClassNotFoundException\n        | NoSuchMethodException\n        | InstantiationException\n        | IllegalAccessException\n        | IllegalArgumentException\n        | InvocationTargetException\n        | SecurityException ignore) {\n    }\n\n    return new JarFile(path);\n  }\n\n  private static void addPreconfLibs(String libs) {\n    URL u =\n        Main.class.getClassLoader().getResource(Main.class.getName().replace('.', '/') + \".class\");\n    if (u != null) {\n      String path = u.toString();\n      int delimiterPos = path.lastIndexOf('!');\n      if (delimiterPos > -1) {\n        String jar = path.substring(9, delimiterPos);\n        File jarFile = new File(jar);\n        Path libRoot = new File(jarFile.getParent() + File.separator + \"btrace-libs\").toPath();\n        Path libFolder = libs != null ? libRoot.resolve(libs) : libRoot;\n        if (Files.exists(libFolder)) {\n          appendToBootClassPath(libFolder);\n          appendToSysClassPath(libFolder);\n        } else {\n          if (libs != null && !libs.isEmpty()) {\n            log.warn(\n                \"Invalid 'libs' configuration [{}]. Path '{}' does not exist.\",\n                libs,\n                libFolder.toAbsolutePath());\n          }\n        }\n      }\n    }\n  }\n\n  private static void appendToBootClassPath(Path libFolder) {\n    Path bootLibs = libFolder.resolve(\"boot\");\n    if (Files.exists(bootLibs)) {\n      try {\n        Files.walkFileTree(\n            bootLibs,\n            new FileVisitor<Path>() {\n              @Override\n              public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)\n                  throws IOException {\n                return FileVisitResult.CONTINUE;\n              }\n\n              @Override\n              public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)\n                  throws IOException {\n                if (file.toString().toLowerCase().endsWith(\".jar\")) {\n                  if (log.isDebugEnabled()) {\n                    log.debug(\"Adding {} to bootstrap classpath\", file);\n                  }\n                  inst.appendToBootstrapClassLoaderSearch(new JarFile(file.toFile()));\n                }\n                return FileVisitResult.CONTINUE;\n              }\n\n              @Override\n              public FileVisitResult visitFileFailed(Path file, IOException exc)\n                  throws IOException {\n                return FileVisitResult.CONTINUE;\n              }\n\n              @Override\n              public FileVisitResult postVisitDirectory(Path dir, IOException exc)\n                  throws IOException {\n                return FileVisitResult.CONTINUE;\n              }\n            });\n      } catch (IOException e) {\n        log.debug(\"Failed to enhance bootstrap classpath\", e);\n      }\n    }\n  }\n\n  private static void appendToSysClassPath(Path libFolder) {\n    Path sysLibs = libFolder.resolve(\"system\");\n    if (Files.exists(sysLibs)) {\n      try {\n        Files.walkFileTree(\n            sysLibs,\n            new FileVisitor<Path>() {\n              @Override\n              public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)\n                  throws IOException {\n                return FileVisitResult.CONTINUE;\n              }\n\n              @Override\n              public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)\n                  throws IOException {\n                if (file.toString().toLowerCase().endsWith(\".jar\")) {\n                  if (log.isDebugEnabled()) {\n                    log.debug(\"Adding {} to system classpath\", file);\n                  }\n                  inst.appendToSystemClassLoaderSearch(new JarFile(file.toFile()));\n                }\n                return FileVisitResult.CONTINUE;\n              }\n\n              @Override\n              public FileVisitResult visitFileFailed(Path file, IOException exc)\n                  throws IOException {\n                return FileVisitResult.CONTINUE;\n              }\n\n              @Override\n              public FileVisitResult postVisitDirectory(Path dir, IOException exc)\n                  throws IOException {\n                return FileVisitResult.CONTINUE;\n              }\n            });\n      } catch (IOException e) {\n        log.debug(\"Failed to enhance sytem classpath\", e);\n      }\n    }\n  }\n\n  private static boolean loadBTraceScript(String filePath, boolean traceToStdOut) {\n    if (!BTraceProbeFactory.canLoad(filePath)) {\n      return false;\n    }\n\n    try {\n      String scriptName = \"\";\n      String scriptParent = \"\";\n      File traceScript = new File(filePath);\n      scriptName = traceScript.getName();\n      scriptParent = traceScript.getParent();\n\n      if (!traceScript.exists()) {\n        traceScript = new File(Constants.EMBEDDED_BTRACE_SECTION_HEADER + filePath);\n      }\n\n      if (scriptName.endsWith(\".java\")) {\n        if (log.isDebugEnabled()) {\n          log.debug(\"refusing {} - script should be a pre-compiled class file\", filePath);\n        }\n        return false;\n      }\n\n      SharedSettings clientSettings = new SharedSettings();\n      clientSettings.from(settings);\n      clientSettings.setClientName(scriptName);\n      if (traceToStdOut) {\n        clientSettings.setOutputFile(\"::stdout\");\n      } else {\n        String traceOutput = clientSettings.getOutputFile();\n        String outDir = clientSettings.getScriptOutputDir();\n        if (traceOutput == null || traceOutput.isEmpty()) {\n          clientSettings.setOutputFile(\"${client}-${agent}.${ts}.btrace[default]\");\n          if (outDir == null || outDir.isEmpty()) {\n            clientSettings.setScriptOutputDir(scriptParent);\n          }\n        }\n      }\n      ClientContext ctx = new ClientContext(inst, transformer, argMap, clientSettings);\n      Client client = new FileClient(ctx, traceScript);\n      if (client.isInitialized()) {\n        handleNewClient(client).get();\n        return true;\n      }\n    } catch (NullPointerException e) {\n      if (log.isDebugEnabled()) {\n        log.debug(\"script {} does not exist!\", filePath, e);\n      }\n    } catch (RuntimeException | IOException | ExecutionException re) {\n      if (log.isDebugEnabled()) {\n        log.debug(\"Failed to load BTrace script {}\", filePath, re);\n      }\n    } catch (InterruptedException e) {\n      Thread.currentThread().interrupt();\n    }\n    return false;\n  }\n\n  // -- Internals only below this point\n  @SuppressWarnings(\"InfiniteLoopStatement\")\n  private static void startServer() {\n    int port = BTRACE_DEFAULT_PORT;\n    String p = argMap.get(PORT);\n    if (p != null) {\n      try {\n        port = Integer.parseInt(p);\n      } catch (NumberFormatException exp) {\n        error(\"invalid port assuming default..\");\n      }\n    }\n    try {\n      if (log.isDebugEnabled()) {\n        log.debug(\"starting server at port {}\", port);\n      }\n      System.setProperty(\"btrace.wireio\", String.valueOf(WireIO.VERSION));\n\n      String scriptOutputFile = settings.getOutputFile();\n      if (scriptOutputFile != null && !scriptOutputFile.isEmpty()) {\n        System.setProperty(\"btrace.output\", scriptOutputFile);\n      }\n      serverSocket = new ServerSocket(port);\n      System.setProperty(\"btrace.port\", String.valueOf(serverSocket.getLocalPort()));\n\n      // Add shutdown hook to close server socket on JVM exit\n      Runtime.getRuntime()\n          .addShutdownHook(\n              new Thread(\n                  () -> {\n                    serverRunning = false;\n                    if (serverSocket != null && !serverSocket.isClosed()) {\n                      try {\n                        serverSocket.close();\n                        log.debug(\"BTrace server socket closed\");\n                      } catch (IOException e) {\n                        log.debug(\"Error closing server socket\", e);\n                      }\n                    }\n                  },\n                  \"BTrace Server Shutdown\"));\n\n    } catch (IOException ioexp) {\n      log.error(\"Failed to start BTrace server on port {}\", port, ioexp);\n      return;\n    }\n\n    while (serverRunning) {\n      try {\n        log.debug(\"waiting for clients\");\n        Socket sock = serverSocket.accept();\n        if (log.isDebugEnabled()) {\n          log.debug(\"client accepted {}\", sock);\n        }\n        ClientContext ctx = new ClientContext(inst, transformer, argMap, settings);\n        Client client = RemoteClient.getClient(ctx, sock, Main::handleNewClient);\n      } catch (RuntimeException | IOException re) {\n        if (serverRunning) {\n          if (log.isDebugEnabled()) {\n            log.debug(\"BTrace server failed\", re);\n          }\n        }\n      }\n    }\n  }\n\n  private static Future<?> handleNewClient(Client client) {\n    return serializedExecutor.submit(\n        () -> {\n          try {\n            boolean entered = BTraceRuntime.enter();\n            try {\n              if (log.isDebugEnabled()) {\n                log.debug(\"new Client created {}\", client);\n              }\n              if (client.retransformLoaded()) {\n                client.getRuntime().sendCommand(new StatusCommand((byte) 1));\n              }\n            } catch (UnmodifiableClassException uce) {\n              log.debug(\"BTrace class retransformation failed\", uce);\n              client.getRuntime().sendCommand(new ErrorCommand(uce));\n              client.getRuntime().sendCommand(new StatusCommand(-1 * StatusCommand.STATUS_FLAG));\n            } finally {\n              if (entered) {\n                BTraceRuntime.leave();\n              }\n            }\n          } catch (Throwable t) {\n            log.warn(\"Unhandled exception in client handler\", t);\n          }\n        });\n  }\n\n  private static void error(String msg) {\n    System.err.println(\"btrace ERROR: \" + msg);\n  }\n\n  private static boolean isDebug() {\n    return settings.isDebug();\n  }\n}\n"
  },
  {
    "path": "btrace-agent/src/main/java/org/openjdk/btrace/agent/PerfReaderImpl.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.agent;\n\nimport java.net.URISyntaxException;\nimport org.openjdk.btrace.runtime.PerfReader;\nimport sun.jvmstat.monitor.IntegerMonitor;\nimport sun.jvmstat.monitor.LongMonitor;\nimport sun.jvmstat.monitor.Monitor;\nimport sun.jvmstat.monitor.MonitorException;\nimport sun.jvmstat.monitor.MonitoredHost;\nimport sun.jvmstat.monitor.MonitoredVm;\nimport sun.jvmstat.monitor.StringMonitor;\nimport sun.jvmstat.monitor.VmIdentifier;\n\nfinal class PerfReaderImpl implements PerfReader {\n  private volatile MonitoredVm thisVm;\n\n  private synchronized MonitoredVm getThisVm() {\n    if (thisVm == null) {\n      try {\n        MonitoredHost localHost = MonitoredHost.getMonitoredHost(\"localhost\");\n        VmIdentifier vmIdent = new VmIdentifier(\"0\");\n        thisVm = localHost.getMonitoredVm(vmIdent);\n      } catch (MonitorException | URISyntaxException me) {\n        throw new IllegalArgumentException(\"jvmstat perf counters not available: \" + me);\n      }\n    }\n    return thisVm;\n  }\n\n  private Monitor findByName(String name) {\n    try {\n      return getThisVm().findByName(name);\n    } catch (Exception e) {\n      throw new RuntimeException(e);\n    }\n  }\n\n  @Override\n  public int perfInt(String name) {\n    Monitor mon = findByName(name);\n    if (mon == null) {\n      throw new IllegalArgumentException(\"no such counter: \" + name);\n    }\n    if (mon instanceof IntegerMonitor) {\n      return ((IntegerMonitor) mon).intValue();\n    } else if (mon instanceof LongMonitor) {\n      return (int) ((LongMonitor) mon).longValue();\n    } else {\n      throw new IllegalArgumentException(name + \" is not an int\");\n    }\n  }\n\n  @Override\n  public long perfLong(String name) {\n    Monitor mon = findByName(name);\n    if (mon == null) {\n      throw new IllegalArgumentException(\"no such counter: \" + name);\n    }\n    if (mon instanceof LongMonitor) {\n      return ((LongMonitor) mon).longValue();\n    } else {\n      throw new IllegalArgumentException(name + \" is not a long\");\n    }\n  }\n\n  @Override\n  public String perfString(String name) {\n    Monitor mon = findByName(name);\n    if (mon == null) {\n      throw new IllegalArgumentException(\"no such counter: \" + name);\n    }\n    if (mon instanceof StringMonitor) {\n      return ((StringMonitor) mon).stringValue();\n    } else {\n      throw new IllegalArgumentException(name + \" is not a string\");\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-agent/src/main/java/org/openjdk/btrace/agent/RemoteClient.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.agent;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.PushbackInputStream;\nimport java.net.Socket;\nimport java.net.SocketException;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicReferenceFieldUpdater;\nimport java.util.concurrent.locks.LockSupport;\nimport org.openjdk.btrace.core.*;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.DisconnectCommand;\nimport org.openjdk.btrace.core.comm.EventCommand;\nimport org.openjdk.btrace.core.comm.ExitCommand;\nimport org.openjdk.btrace.core.comm.InstrumentCommand;\nimport org.openjdk.btrace.core.comm.BinaryWireProtocol;\nimport org.openjdk.btrace.core.comm.JavaSerializationProtocol;\nimport org.openjdk.btrace.core.comm.ListFailedExtensionsCommand;\nimport org.openjdk.btrace.core.comm.ListProbesCommand;\nimport org.openjdk.btrace.core.comm.PrintableCommand;\nimport org.openjdk.btrace.core.comm.ProtocolConfig;\nimport org.openjdk.btrace.core.comm.ProtocolNegotiator;\nimport org.openjdk.btrace.core.comm.ProtocolVersion;\nimport org.openjdk.btrace.core.comm.ReconnectCommand;\nimport org.openjdk.btrace.core.comm.SetSettingsCommand;\nimport org.openjdk.btrace.core.comm.StatusCommand;\nimport org.openjdk.btrace.core.comm.WireProtocol;\nimport org.openjdk.btrace.extension.ExtensionRegistry;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Represents a remote client communicated by socket.\n *\n * @author A. Sundararajan\n */\n@SuppressWarnings({\"SynchronizeOnNonFinalField\", \"SynchronizationOnLocalVariableOrMethodParameter\"})\nclass RemoteClient extends Client {\n  private static final Logger log = LoggerFactory.getLogger(RemoteClient.class);\n\n  private final class DelayedCommandExecutor implements Function<Command, Boolean> {\n    private final boolean isConnected;\n\n    public DelayedCommandExecutor(boolean isConnected) {\n      this.isConnected = isConnected;\n    }\n\n    @Override\n    public Boolean apply(Command value) {\n      return dispatchCommand(value, isConnected);\n    }\n  }\n\n  private volatile Socket sock;\n  private volatile WireProtocol protocol;\n  private volatile boolean disconnected = false;\n  private final AtomicReferenceFieldUpdater<RemoteClient, Socket> sockUpdater =\n      AtomicReferenceFieldUpdater.newUpdater(RemoteClient.class, Socket.class, \"sock\");\n  private final AtomicReferenceFieldUpdater<RemoteClient, WireProtocol> protocolUpdater =\n      AtomicReferenceFieldUpdater.newUpdater(RemoteClient.class, WireProtocol.class, \"protocol\");\n\n  private final CircularBuffer<Command> delayedCommands = new CircularBuffer<>(5000);\n\n  static Client getClient(ClientContext ctx, Socket sock, Function<Client, Future<?>> initCallback)\n      throws IOException {\n    SharedSettings settings = ctx.getSettings();\n    ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n    InputStream rawInput = sock.getInputStream();\n    OutputStream output = sock.getOutputStream();\n    ProtocolNegotiator negotiator = new ProtocolNegotiator(config.getVersion());\n    PushbackInputStream input = ProtocolNegotiator.createNegotiationStream(rawInput);\n    ProtocolVersion negotiated;\n    if (config.isAutoNegotiate()) {\n      negotiated = negotiator.negotiateAgent(input, output);\n    } else if (config.getVersion() == ProtocolVersion.V2) {\n      negotiated = negotiator.negotiateAgent(input, output);\n      if (negotiated != ProtocolVersion.V2) {\n        throw new IOException(\"Protocol negotiation failed: expected V2\");\n      }\n    } else {\n      negotiated = ProtocolVersion.V1;\n    }\n\n    WireProtocol wireProtocol =\n        negotiated == ProtocolVersion.V2\n            ? new BinaryWireProtocol(input, output)\n            : new JavaSerializationProtocol(input, output);\n\n    while (true) {\n      Command cmd;\n      try {\n        cmd = wireProtocol.read();\n      } catch (ClassNotFoundException e) {\n        throw new IOException(e);\n      }\n      switch (cmd.getType()) {\n        case Command.SET_PARAMS:\n          {\n            settings.from(((SetSettingsCommand) cmd).getParams());\n            break;\n          }\n        case Command.INSTRUMENT:\n          {\n            log.debug(\"got instrument command\");\n            try {\n              Client client = new RemoteClient(ctx, wireProtocol, sock, (InstrumentCommand) cmd);\n              initCallback.apply(client).get();\n              client.sendCommand(new StatusCommand(StatusCommand.STATUS_FLAG));\n              return client;\n            } catch (ExecutionException | InterruptedException e) {\n              wireProtocol.write(new StatusCommand(-1 * StatusCommand.STATUS_FLAG));\n              throw new IOException(e);\n            }\n          }\n        case Command.RECONNECT:\n          {\n            String probeId = ((ReconnectCommand) cmd).getProbeId();\n            log.debug(\"Attempting to reconnect client for probe {}\", probeId);\n            Client client = Client.findClient(probeId);\n            log.debug(\"Found client {}\", client);\n            if (client instanceof RemoteClient) {\n              ((RemoteClient) client).reconnect(wireProtocol, sock);\n              client.sendCommand(new StatusCommand(ReconnectCommand.STATUS_FLAG));\n              return client;\n            }\n            wireProtocol.write(new StatusCommand(-1 * ReconnectCommand.STATUS_FLAG));\n            throw new IOException(\"Can not reconnect to non-remote session\");\n          }\n        case Command.LIST_PROBES:\n          {\n            ListProbesCommand listProbesCommand = (ListProbesCommand) cmd;\n            listProbesCommand.setProbes(Client.listProbes());\n            wireProtocol.write(listProbesCommand);\n            break;\n          }\n        case Command.LIST_FAILED_EXTENSIONS:\n          {\n            ListFailedExtensionsCommand listFailedCmd = (ListFailedExtensionsCommand) cmd;\n            listFailedCmd.setFailedExtensions(ExtensionRegistry.getFailedExtensions());\n            wireProtocol.write(listFailedCmd);\n            break;\n          }\n        case Command.EXIT:\n          {\n            return null;\n          }\n        default:\n          {\n            throw new IOException(\n                \"expecting instrument, reconnect or settings command! (\" + cmd.getClass() + \")\");\n          }\n      }\n    }\n  }\n\n  private RemoteClient(\n      ClientContext ctx,\n      WireProtocol protocol,\n      Socket sock,\n      InstrumentCommand cmd)\n      throws IOException {\n    super(ctx);\n    this.sock = sock;\n    this.protocol = protocol;\n    this.settings.from(ctx.getSettings());\n    Class<?> btraceClazz = loadClass(cmd);\n    if (btraceClazz == null) {\n      throw new RuntimeException(\"can not load BTrace class\");\n    }\n\n    initClient();\n  }\n\n  private void initClient() {\n    BTraceRuntime.initUnsafe();\n    Thread cmdHandler =\n        new Thread(\n            () -> {\n              try {\n                BTraceRuntime.enter();\n                while (true) {\n                  try {\n                    if (protocol == null) {\n                      LockSupport.parkNanos(500_000_000L); // sleep 500ms\n                      continue;\n                    }\n                    Command cmd = protocol.read();\n                    switch (cmd.getType()) {\n                      case Command.EXIT:\n                        {\n                          log.debug(\"received exit command\");\n                          onCommand(cmd);\n\n                          return;\n                        }\n                      case Command.DISCONNECT:\n                        {\n                          log.debug(\"received disconnect command\");\n                          onCommand(cmd);\n                          break;\n                        }\n                      case Command.LIST_PROBES:\n                        {\n                          onCommand(cmd);\n                          break;\n                        }\n                      case Command.LIST_FAILED_EXTENSIONS:\n                        {\n                          onCommand(cmd);\n                          break;\n                        }\n                      case Command.EVENT:\n                        {\n                          BTraceRuntime.Impl rt = getRuntime();\n                          if (rt != null) {\n                            rt.handleEvent((EventCommand) cmd);\n                          }\n                          break;\n                        }\n                      default:\n                        if (log.isDebugEnabled()) {\n                          log.debug(\"received {}\", cmd);\n                        }\n                        // ignore any other command\n                    }\n                  } catch (Exception exp) {\n                    // When the client disconnects normally, ObjectInputStream.read may throw\n                    // EOFException. Treat it as a clean shutdown and avoid noisy stack traces\n                    // that end up in target stderr during debug runs.\n                    if (exp instanceof java.io.EOFException || exp instanceof SocketException) {\n                      if (log.isDebugEnabled()) {\n                        log.debug(\"client command stream closed: {}\", exp.toString());\n                      }\n                    } else {\n                      log.debug(\"Error while processing BTrace command\", exp);\n                    }\n                    break;\n                  }\n                }\n              } finally {\n                BTraceRuntime.leave();\n                try {\n                  // Ensure streams and socket are closed once the client side closed first.\n                  closeAll();\n                } catch (IOException ignore) {\n                  // best effort\n                }\n              }\n            });\n    cmdHandler.setDaemon(true);\n    log.debug(\"starting client command handler thread\");\n    cmdHandler.start();\n  }\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  public void onCommand(Command cmd) throws IOException {\n    WireProtocol output = protocol;\n    if (output == null) {\n      if (!cmd.isUrgent()) {\n        delayedCommands.add(cmd);\n      }\n      return;\n    }\n    if (log.isDebugEnabled()) {\n      log.debug(\"client {}: got {}\", getClassName(), cmd);\n    }\n    boolean isConnected = true;\n    try {\n      synchronized (output) {\n        output.flush();\n      }\n    } catch (IOException e) {\n      isConnected = false;\n    }\n\n    delayedCommands.forEach(new DelayedCommandExecutor(isConnected));\n\n    if (!dispatchCommand(cmd, isConnected)) {\n      if (!cmd.isUrgent()) {\n        delayedCommands.add(cmd);\n      }\n    }\n  }\n\n  private boolean dispatchCommand(Command cmd, boolean isConnected) {\n    if (cmd == Command.NULL) {\n      return true; // do not dispatch the NULL command\n    }\n    WireProtocol output = protocol;\n    Socket socket = sock;\n    if (output == null) {\n      return false;\n    }\n    try {\n      switch (cmd.getType()) {\n        case Command.EXIT:\n          if (isConnected) {\n            output.write(cmd);\n          }\n          onExit(((ExitCommand) cmd).getExitCode());\n          break;\n        case Command.LIST_PROBES:\n          {\n            if (isConnected) {\n              ((ListProbesCommand) cmd).setProbes(listProbes());\n              output.write(cmd);\n            }\n            break;\n          }\n        case Command.LIST_FAILED_EXTENSIONS:\n          {\n            if (isConnected) {\n              ((ListFailedExtensionsCommand) cmd).setFailedExtensions(\n                  ExtensionRegistry.getFailedExtensions());\n              output.write(cmd);\n            }\n            break;\n          }\n        case Command.DISCONNECT:\n          {\n            ((DisconnectCommand) cmd).setProbeId(id.toString());\n            synchronized (output) {\n              output.write(cmd);\n              output.flush();\n              try {\n                // Half-close the output to allow the client to read DISCONNECT reliably\n                if (socket != null && !socket.isClosed()) {\n                  socket.shutdownOutput();\n                }\n              } catch (IOException ioe) {\n                // ignore; best effort\n              }\n            }\n            if (log.isDebugEnabled()) {\n              log.debug(\"sent DISCONNECT to client and shutdown socket output\");\n            }\n            disconnected = true;\n            break;\n          }\n        default:\n          if (out != null) {\n            if (cmd instanceof PrintableCommand) {\n              ((PrintableCommand) cmd).print(out);\n              break;\n            }\n          }\n          if (isConnected) {\n            output.write(cmd);\n          }\n      }\n      return true;\n    } catch (IOException e) {\n      return false;\n    }\n  }\n\n  public boolean isDisconnected() {\n    return disconnected;\n  }\n\n  @Override\n  protected void sendCommand(Command command) {\n    if (getRuntime() != null) {\n      super.sendCommand(command);\n      return;\n    }\n    // Runtime not yet initialized - send directly via protocol\n    WireProtocol output = protocol;\n    if (output != null) {\n      try {\n        synchronized (output) {\n          output.write(command);\n          output.flush();\n        }\n      } catch (IOException e) {\n        log.warn(\"Failed to send command {} via protocol\", command.getClass().getSimpleName(), e);\n      }\n    } else {\n      log.warn(\"Cannot send command {}, neither runtime nor protocol available\",\n          command.getClass().getSimpleName());\n    }\n  }\n\n  @Override\n  protected void closeAll() throws IOException {\n    super.closeAll();\n    disconnected = true;\n\n    WireProtocol output = protocol;\n    if (output != null) {\n      output.close();\n      protocolUpdater.compareAndSet(this, output, null);\n    }\n    Socket socket = sock;\n    if (socket != null) {\n      socket.close();\n      sockUpdater.compareAndSet(this, socket, null);\n    }\n  }\n\n  void reconnect(WireProtocol protocol, Socket socket) throws IOException {\n    this.sock = socket;\n    this.protocol = protocol;\n    this.disconnected = false;\n    onCommand(Command.NULL);\n  }\n}\n"
  },
  {
    "path": "btrace-agent/src/main/java/org/openjdk/btrace/agent/TraceOutputWriter.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.agent;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class represents various strategies available for dumping BTrace output to a file.\n *\n * @author Jaroslav Bachorik\n */\nabstract class TraceOutputWriter extends Writer {\n  private static final Logger log = LoggerFactory.getLogger(TraceOutputWriter.class);\n\n  protected TraceOutputWriter() {}\n\n  /**\n   * Plain file writer - all output will go to one specified file\n   *\n   * @param output The file to put the output to\n   * @return Returns an appropriate {@linkplain TraceOutputWriter} instance or NULL\n   */\n  public static TraceOutputWriter fileWriter(File output) {\n    TraceOutputWriter instance = null;\n    try {\n      instance = new SimpleFileWriter(output);\n    } catch (IOException e) {\n      // ignore\n    }\n    return instance;\n  }\n\n  /**\n   * Time based rolling file writer. Defaults to 100 allowed output chunks.\n   *\n   * @param output The file to put the output to\n   * @param settings The shared settings\n   * @return Returns an appropriate {@linkplain TraceOutputWriter} instance or NULL\n   */\n  public static TraceOutputWriter rollingFileWriter(File output, SharedSettings settings) {\n    TraceOutputWriter instance = null;\n    try {\n      instance = new TimeBasedRollingFileWriter(output, settings);\n    } catch (IOException e) {\n      // ignore\n    }\n    return instance;\n  }\n\n  private static void ensurePathExists(File f) {\n    if (f == null || f.exists()) return;\n\n    ensurePathExists(f.getParentFile());\n\n    if (!f.getName().endsWith(\".btrace\")) { // not creating the actual file\n      try {\n        f.createNewFile();\n      } catch (IOException e) {\n        log.debug(\"Failed to create directory: {}\", f, e);\n        // ignore and continue\n      }\n    }\n  }\n\n  private static class SimpleFileWriter extends TraceOutputWriter {\n    private static final Logger log = LoggerFactory.getLogger(SimpleFileWriter.class);\n\n    private final FileWriter delegate;\n\n    @SuppressWarnings(\"DefaultCharset\")\n    public SimpleFileWriter(File output) throws IOException {\n      try {\n        File parent = output.getParentFile();\n        if (parent != null) {\n          output.getParentFile().mkdirs();\n        }\n        delegate = new FileWriter(output);\n      } catch (IOException e) {\n        log.debug(\"Failed to create file output {}\", output.getName(), e);\n        throw e;\n      }\n    }\n\n    @Override\n    public void close() throws IOException {\n      delegate.close();\n    }\n\n    @Override\n    public void flush() throws IOException {\n      delegate.flush();\n    }\n\n    @Override\n    public void write(char[] cbuf, int off, int len) throws IOException {\n      delegate.write(cbuf, off, len);\n    }\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  private abstract static class RollingFileWriter extends TraceOutputWriter {\n    private static final Logger log = LoggerFactory.getLogger(RollingFileWriter.class);\n    protected final SharedSettings settings;\n    private final ReentrantReadWriteLock writerLock = new ReentrantReadWriteLock();\n    private final String path, baseName;\n    // @GuardedBy writerLock\n    private FileWriter currentFileWriter;\n    private int counter = 1;\n\n    public RollingFileWriter(File output, SharedSettings settings) throws IOException {\n      try {\n        output.getParentFile().mkdirs();\n        currentFileWriter = new FileWriter(output);\n        path = output.getParentFile().getAbsolutePath();\n        baseName = output.getName();\n        this.settings = settings;\n      } catch (IOException e) {\n        log.debug(\"Failed to create rolling file output {}\", output.getName(), e);\n        throw e;\n      }\n    }\n\n    @Override\n    public final void close() throws IOException {\n      try {\n        writerLock.readLock().lock();\n        currentFileWriter.close();\n      } finally {\n        writerLock.readLock().unlock();\n      }\n    }\n\n    @Override\n    public final void flush() throws IOException {\n      try {\n        writerLock.readLock().lock();\n        currentFileWriter.flush();\n      } finally {\n        writerLock.readLock().unlock();\n      }\n\n      if (needsRoll()) {\n        nextWriter();\n      }\n    }\n\n    @Override\n    public final void write(char[] cbuf, int off, int len) throws IOException {\n      try {\n        writerLock.readLock().lock();\n        currentFileWriter.write(cbuf, off, len);\n      } finally {\n        writerLock.readLock().unlock();\n      }\n    }\n\n    private void nextWriter() {\n      try {\n        writerLock.writeLock().lock();\n        currentFileWriter = getNextWriter();\n      } catch (IOException e) {\n        log.debug(\"Failed to roll over\", e);\n      } finally {\n        writerLock.writeLock().unlock();\n      }\n    }\n\n    private FileWriter getNextWriter() throws IOException {\n      currentFileWriter.close();\n      File scriptOutputFile_renameFrom = new File(path + File.separator + baseName);\n      File scriptOutputFile_renameTo =\n          new File(path + File.separator + baseName + \".\" + (counter++));\n\n      if (scriptOutputFile_renameTo.exists()) {\n        scriptOutputFile_renameTo.delete();\n      }\n      scriptOutputFile_renameFrom.renameTo(scriptOutputFile_renameTo);\n      scriptOutputFile_renameFrom = new File(path + File.separator + baseName);\n      if (counter > settings.getFileRollMaxRolls()) {\n        counter = 1;\n      }\n      return new FileWriter(scriptOutputFile_renameFrom);\n    }\n\n    protected abstract boolean needsRoll();\n  }\n\n  private static class TimeBasedRollingFileWriter extends RollingFileWriter {\n    private final TimeUnit unit = TimeUnit.MILLISECONDS;\n    private long lastTimeStamp = System.currentTimeMillis();\n\n    public TimeBasedRollingFileWriter(File output, SharedSettings settings) throws IOException {\n      super(output, settings);\n    }\n\n    @Override\n    protected boolean needsRoll() {\n      long currTime = System.currentTimeMillis();\n      long myInterval = currTime - lastTimeStamp;\n      if (unit.convert(myInterval, TimeUnit.MILLISECONDS) >= settings.getFileRollMilliseconds()) {\n        lastTimeStamp = currTime;\n        return true;\n      }\n      return false;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-agent/src/main/resources/META-INF/MANIFEST.MF",
    "content": "Premain-Class: org.openjdk.btrace.agent.Main\nAgent-Class: org.openjdk.btrace.agent.Main\nCan-Redefine-Classes: true\nCan-Retransform-Classes: true\nBoot-Class-Path: btrace-boot.jar\n"
  },
  {
    "path": "btrace-agent/src/test/java/org/openjdk/btrace/agent/MainTest.java",
    "content": "package org.openjdk.btrace.agent;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.List;\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.ArgsMap;\n\nclass MainTest {\n  @Test\n  void locateScriptsEmpty() {\n    ArgsMap argsMap = new ArgsMap();\n    List<String> scripts = Main.locateScripts(argsMap);\n\n    assertTrue(scripts.isEmpty());\n  }\n\n  @Test\n  void locateScriptsSingle() {\n    ArgsMap argsMap = new ArgsMap(new String[] {\"script=script1\"});\n    List<String> scripts = Main.locateScripts(argsMap);\n\n    assertEquals(1, scripts.size());\n  }\n\n  @Test\n  void locateScriptsMulti() {\n    ArgsMap argsMap = new ArgsMap(new String[] {\"script=script1:script2\"});\n    List<String> scripts = Main.locateScripts(argsMap);\n\n    assertEquals(2, scripts.size());\n  }\n\n  @Test\n  void locateScriptsDir() throws Exception {\n    Path dir = Files.createTempDirectory(\"test-\");\n    Path script = Files.createTempFile(dir, \"script-\", \".btrace\");\n    ArgsMap argsMap = new ArgsMap(new String[] {\"scriptdir=\" + dir.toString()});\n    List<String> scripts = Main.locateScripts(argsMap);\n\n    assertEquals(1, scripts.size());\n  }\n}\n"
  },
  {
    "path": "btrace-api/build.gradle",
    "content": "// BTrace API module for compile-time dependencies\n// This module provides the compile-time API for BTrace scripts\n\ndependencies {\n    implementation project(':btrace-core')\n    implementation project(':btrace-compiler')\n}\n"
  },
  {
    "path": "btrace-boot/build.gradle",
    "content": "plugins {\n    id 'java-library'\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(8))\n    }\n}\n\njar {\n    manifest {\n        attributes(\n            'Premain-Class': 'org.openjdk.btrace.boot.Loader',\n            'Agent-Class': 'org.openjdk.btrace.boot.Loader',\n            'Main-Class': 'org.openjdk.btrace.boot.Loader',\n            'Can-Redefine-Classes': true,\n            'Can-Retransform-Classes': true\n        )\n    }\n}\n"
  },
  {
    "path": "btrace-boot/src/main/java/org/openjdk/btrace/boot/Loader.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.boot;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.instrument.Instrumentation;\nimport java.lang.reflect.Method;\nimport java.net.URL;\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\n/**\n * Entry point and classloader for the masked JAR structure.\n * <p>\n * This class serves as the single entry point for btrace.jar in all modes:\n * <ul>\n *   <li>Agent mode: {@code -javaagent:btrace.jar} calls {@link #premain(String, Instrumentation)}</li>\n *   <li>Dynamic attach: calls {@link #agentmain(String, Instrumentation)}</li>\n *   <li>Client mode: {@code java -jar btrace.jar} calls {@link #main(String[])}</li>\n * </ul>\n * <p>\n * The JAR structure uses .classdata extension for non-bootstrap classes to hide them\n * from the bootstrap classloader while keeping everything in a single JAR:\n * <pre>\n * btrace.jar\n * ├── org/openjdk/btrace/boot/Loader.class      (bootstrap: this class)\n * ├── org/openjdk/btrace/core/*.class           (bootstrap: core API)\n * ├── org/openjdk/btrace/runtime/*.class        (bootstrap: runtime)\n * ├── META-INF/btrace/agent/*.classdata         (masked: agent classes)\n * └── META-INF/btrace/client/*.classdata        (masked: client classes)\n * </pre>\n *\n * @author Jaroslav Bachorik\n */\npublic final class Loader {\n\n    private static final String AGENT_SECTION = \"agent\";\n    private static final String CLIENT_SECTION = \"client\";\n    private static final String AGENT_MAIN_ATTR = \"BTrace-Agent-Main\";\n    private static final String CLIENT_MAIN_ATTR = \"BTrace-Client-Main\";\n    private static final String DEFAULT_AGENT_MAIN = \"org.openjdk.btrace.agent.Main\";\n    private static final String DEFAULT_CLIENT_MAIN = \"org.openjdk.btrace.client.Main\";\n    private static final boolean DEBUG = Boolean.getBoolean(\"btrace.boot.debug\");\n\n    private Loader() {\n        // Utility class\n    }\n\n    /**\n     * Agent entry point for load-time instrumentation.\n     *\n     * @param args command line arguments\n     * @param inst instrumentation instance\n     */\n    public static void premain(String args, Instrumentation inst) {\n        debug(\"premain called with args: \" + args);\n        startAgent(args, inst, \"premain\");\n    }\n\n    /**\n     * Agent entry point for dynamic attach.\n     *\n     * @param args command line arguments\n     * @param inst instrumentation instance\n     */\n    public static void agentmain(String args, Instrumentation inst) {\n        debug(\"agentmain called with args: \" + args);\n        startAgent(args, inst, \"agentmain\");\n    }\n\n    /**\n     * Client entry point for command-line usage.\n     *\n     * @param args command line arguments\n     */\n    public static void main(String[] args) {\n        debug(\"main called\");\n        startClient(args);\n    }\n\n    private static void startAgent(String args, Instrumentation inst, String methodName) {\n        try {\n            debug(\"startAgent called with args: \" + args);\n\n            // Get JAR file location (tries CodeSource, then getResource() fallback)\n            File jarFile = getJarFile();\n            if (jarFile == null) {\n                throw new RuntimeException(\"Cannot locate btrace.jar\");\n            }\n            debug(\"Loading agent from: \" + jarFile.getAbsolutePath());\n\n            // Add btrace.jar to bootstrap classloader search path\n            // This is required so that bootstrap-visible classes (BTraceRuntimeAccess, Auxiliary, etc.)\n            // are visible to probe classes which are defined via bootstrap classloader\n            try {\n                inst.appendToBootstrapClassLoaderSearch(new JarFile(jarFile));\n                debug(\"Added btrace.jar to bootstrap classpath\");\n            } catch (IOException e) {\n                debug(\"WARNING: Failed to add btrace.jar to bootstrap classpath: \" + e.getMessage());\n            }\n\n            // Read main class from manifest\n            String mainClass = getManifestAttribute(jarFile, AGENT_MAIN_ATTR, DEFAULT_AGENT_MAIN);\n            debug(\"Agent main class: \" + mainClass);\n\n            // Create classloader for agent section\n            // Use null (bootstrap) as parent to ensure bootstrap classes like BTraceRuntimeAccess\n            // are loaded from bootstrap (via appendToBootstrapClassLoaderSearch), not from\n            // Loader's classloader. This ensures probe classes (loaded by bootstrap) see the\n            // same BTraceRuntimeAccess class that the agent uses.\n            MaskedClassLoader agentLoader = new MaskedClassLoader(\n                    jarFile, AGENT_SECTION, null);\n\n            // Load and invoke agent main class\n            Class<?> agentMain = agentLoader.loadClass(mainClass);\n            debug(\"Loaded agent main class: \" + agentMain.getName());\n\n            Method method = agentMain.getMethod(methodName, String.class, Instrumentation.class);\n            method.invoke(null, args, inst);\n            debug(\"Successfully invoked agent main\");\n\n        } catch (Exception e) {\n            System.err.println(\"BTrace agent initialization failed: \" + e.getMessage());\n            e.printStackTrace();\n            throw new RuntimeException(\"BTrace agent initialization failed\", e);\n        }\n    }\n\n    private static void startClient(String[] args) {\n        try {\n            File jarFile = getJarFile();\n            if (jarFile == null) {\n                throw new RuntimeException(\"Cannot locate btrace.jar\");\n            }\n            debug(\"Loading client from: \" + jarFile);\n\n            // Set system property with btrace.jar location so client can use it as agent JAR\n            System.setProperty(\"btrace.jar.path\", jarFile.getAbsolutePath());\n            debug(\"Set btrace.jar.path property to: \" + jarFile.getAbsolutePath());\n\n            // Read main class from manifest\n            String mainClass = getManifestAttribute(jarFile, CLIENT_MAIN_ATTR, DEFAULT_CLIENT_MAIN);\n            debug(\"Client main class: \" + mainClass);\n\n            // Create classloader for client section\n            MaskedClassLoader clientLoader = new MaskedClassLoader(\n                    jarFile, CLIENT_SECTION, Loader.class.getClassLoader());\n\n            // Load and invoke client main class\n            Class<?> clientMain = clientLoader.loadClass(mainClass);\n            Method method = clientMain.getMethod(\"main\", String[].class);\n            method.invoke(null, (Object) args);\n\n        } catch (Exception e) {\n            System.err.println(\"BTrace client initialization failed: \" + e.getMessage());\n            e.printStackTrace();\n            System.exit(1);\n        }\n    }\n\n    private static String getManifestAttribute(File jarFile, String name, String defaultValue) {\n        try (JarFile jar = new JarFile(jarFile)) {\n            Manifest manifest = jar.getManifest();\n            if (manifest != null) {\n                Attributes attrs = manifest.getMainAttributes();\n                String value = attrs.getValue(name);\n                if (value != null && !value.isEmpty()) {\n                    return value;\n                }\n            }\n        } catch (IOException e) {\n            debug(\"Failed to read manifest: \" + e.getMessage());\n        }\n        return defaultValue;\n    }\n\n    private static File getJarFile() {\n        try {\n            // Try CodeSource first\n            ProtectionDomain pd = Loader.class.getProtectionDomain();\n            CodeSource cs = pd.getCodeSource();\n            if (cs != null) {\n                URL location = cs.getLocation();\n                if (location != null) {\n                    debug(\"CodeSource location: \" + location);\n                    if (\"file\".equals(location.getProtocol())) {\n                        return new File(location.toURI());\n                    }\n                    debug(\"Unsupported protocol: \" + location.getProtocol());\n                }\n            }\n\n            // Fallback: use getResource() to find Loader.class in the JAR\n            debug(\"CodeSource unavailable, trying getResource()\");\n            URL loaderResource = Loader.class.getResource(\"Loader.class\");\n            if (loaderResource != null) {\n                debug(\"Loader resource: \" + loaderResource);\n                String path = loaderResource.toString();\n                if (path.startsWith(\"jar:file:\")) {\n                    // Extract JAR path from jar:file:/path/to/btrace.jar!/org/openjdk/btrace/boot/Loader.class\n                    path = path.substring(\"jar:file:\".length());\n                    int idx = path.indexOf(\"!\");\n                    if (idx > -1) {\n                        path = path.substring(0, idx);\n                        return new File(path);\n                    }\n                }\n            }\n\n            debug(\"Could not locate JAR file\");\n            return null;\n        } catch (Exception e) {\n            debug(\"Error getting JAR file: \" + e.getMessage());\n            return null;\n        }\n    }\n\n    private static void debug(String msg) {\n        if (DEBUG) {\n            System.err.println(\"[BTrace Boot] \" + msg);\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-boot/src/main/java/org/openjdk/btrace/boot/MaskedClassLoader.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.boot;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\nimport java.util.Enumeration;\nimport java.util.NoSuchElementException;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\n/**\n * ClassLoader that loads classes from .classdata files in a masked section of a JAR.\n * <p>\n * This classloader reads class bytecode from files stored as .classdata instead of .class,\n * allowing them to be hidden from the bootstrap classloader while remaining in the same JAR.\n * <p>\n * The masked JAR structure has the following sections:\n * <ul>\n *   <li>Bootstrap section: Classes stored as .class files, loaded by bootstrap classloader</li>\n *   <li>Shared section: Classes stored as .classdata files in META-INF/btrace/shared/</li>\n *   <li>Agent section: Classes stored as .classdata files in META-INF/btrace/agent/</li>\n *   <li>Client section: Classes stored as .classdata files in META-INF/btrace/client/</li>\n * </ul>\n * <p>\n * When loading a class, this classloader first checks the specific section (agent or client),\n * then falls back to the shared section, and finally delegates to the parent classloader.\n *\n * @author Jaroslav Bachorik\n */\npublic final class MaskedClassLoader extends URLClassLoader {\n    private static final boolean DEBUG = Boolean.getBoolean(\"btrace.boot.debug\");\n    private final JarFile jarFile;\n    private final File jarPath;\n    private final String sectionPrefix;\n\n    /**\n     * Creates a new MaskedClassLoader.\n     *\n     * @param jarPath path to the JAR file\n     * @param section section name (\"agent\" or \"client\")\n     * @param parent  parent classloader\n     * @throws IOException if the JAR file cannot be opened\n     */\n    public MaskedClassLoader(File jarPath, String section, ClassLoader parent) throws IOException {\n        // Pass empty URL array to avoid URLClassLoader finding regular .class files from btrace.jar\n        // We only want to load from .classdata files (via findClass), delegating all else to parent\n        super(new URL[0], parent);\n        this.jarPath = jarPath;\n        this.jarFile = new JarFile(jarPath);\n        this.sectionPrefix = \"META-INF/btrace/\" + section + \"/\";\n        debug(\"Created MaskedClassLoader for section: \" + section);\n    }\n\n    /**\n     * Gets the JAR file this classloader is reading from.\n     *\n     * @return the JAR file\n     */\n    public JarFile getJarFile() {\n        return jarFile;\n    }\n\n    /**\n     * Gets the path to the JAR file.\n     *\n     * @return the JAR file path\n     */\n    public File getJarPath() {\n        return jarPath;\n    }\n\n    @Override\n    protected Class<?> findClass(String name) throws ClassNotFoundException {\n        debug(\"findClass: \" + name);\n\n        // Convert class name to path: org.foo.Bar -> META-INF/btrace/agent/org/foo/Bar.classdata\n        String classPath = name.replace('.', '/') + \".classdata\";\n\n        // Try specific section first (agent or client)\n        String path = sectionPrefix + classPath;\n        JarEntry entry = jarFile.getJarEntry(path);\n\n        // If not found in specific section, try shared section\n        if (entry == null) {\n            path = \"META-INF/btrace/shared/\" + classPath;\n            entry = jarFile.getJarEntry(path);\n            if (entry != null) {\n                debug(\"Class found in shared section: \" + name);\n            }\n        }\n\n        if (entry == null) {\n            debug(\"Class not found in masked sections: \" + name);\n            throw new ClassNotFoundException(name);\n        }\n\n        try {\n            byte[] bytes = readEntry(entry);\n            debug(\"Loaded \" + bytes.length + \" bytes for class: \" + name);\n\n            // Define the class with a CodeSource pointing to the JAR\n            URL jarUrl = jarPath.toURI().toURL();\n            CodeSource codeSource = new CodeSource(jarUrl, (java.security.cert.Certificate[]) null);\n            ProtectionDomain pd = new ProtectionDomain(codeSource, null, this, null);\n\n            return defineClass(name, bytes, 0, bytes.length, pd);\n        } catch (IOException e) {\n            throw new ClassNotFoundException(name, e);\n        }\n    }\n\n    @Override\n    public URL findResource(String name) {\n        debug(\"findResource: \" + name);\n\n        // First check for the resource in the masked section\n        String maskedPath = sectionPrefix + name;\n        JarEntry entry = jarFile.getJarEntry(maskedPath);\n        if (entry != null) {\n            try {\n                return createJarEntryURL(maskedPath);\n            } catch (MalformedURLException e) {\n                debug(\"Failed to create URL for: \" + maskedPath);\n            }\n        }\n\n        // Fall back to regular resource lookup\n        entry = jarFile.getJarEntry(name);\n        if (entry != null) {\n            try {\n                return createJarEntryURL(name);\n            } catch (MalformedURLException e) {\n                debug(\"Failed to create URL for: \" + name);\n            }\n        }\n\n        return null;\n    }\n\n    @Override\n    public Enumeration<URL> findResources(String name) throws IOException {\n        debug(\"findResources: \" + name);\n\n        final URL resource = findResource(name);\n        return new Enumeration<URL>() {\n            private boolean hasMore = (resource != null);\n\n            @Override\n            public boolean hasMoreElements() {\n                return hasMore;\n            }\n\n            @Override\n            public URL nextElement() {\n                if (!hasMore) {\n                    throw new NoSuchElementException();\n                }\n                hasMore = false;\n                return resource;\n            }\n        };\n    }\n\n    @Override\n    public InputStream getResourceAsStream(String name) {\n        debug(\"getResourceAsStream: \" + name);\n\n        // First check in the masked section\n        String maskedPath = sectionPrefix + name;\n        JarEntry entry = jarFile.getJarEntry(maskedPath);\n        if (entry != null) {\n            try {\n                return jarFile.getInputStream(entry);\n            } catch (IOException e) {\n                debug(\"Failed to get stream for: \" + maskedPath);\n            }\n        }\n\n        // Fall back to regular resource lookup\n        entry = jarFile.getJarEntry(name);\n        if (entry != null) {\n            try {\n                return jarFile.getInputStream(entry);\n            } catch (IOException e) {\n                debug(\"Failed to get stream for: \" + name);\n            }\n        }\n\n        return null;\n    }\n\n    private byte[] readEntry(JarEntry entry) throws IOException {\n        try (InputStream is = jarFile.getInputStream(entry)) {\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            byte[] buffer = new byte[8192];\n            int bytesRead;\n            while ((bytesRead = is.read(buffer)) != -1) {\n                baos.write(buffer, 0, bytesRead);\n            }\n            return baos.toByteArray();\n        }\n    }\n\n    private URL createJarEntryURL(String entryPath) throws MalformedURLException {\n        // Create a jar: URL for the entry\n        return new URL(\"jar:\" + jarPath.toURI().toURL() + \"!/\" + entryPath);\n    }\n\n    @Override\n    public void close() throws IOException {\n        super.close();\n        jarFile.close();\n    }\n\n    private void debug(String msg) {\n        if (DEBUG) {\n            System.err.println(\"[BTrace Boot] [MaskedCL:\" + sectionPrefix + \"] \" + msg);\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-boot/src/main/java/org/openjdk/btrace/boot/MaskedJarUtils.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.boot;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.jar.JarFile;\n\n/**\n * Utility methods for working with masked JAR files.\n *\n * @author Jaroslav Bachorik\n */\npublic final class MaskedJarUtils {\n    private MaskedJarUtils() {\n        // Utility class\n    }\n\n    /**\n     * Finds a masked JAR file in the given classpath.\n     * A masked JAR is identified by containing META-INF/btrace/shared/ directory.\n     *\n     * @param classPath the classpath string (File.pathSeparator separated)\n     * @return the masked JAR file, or null if not found\n     */\n    public static File findMaskedJarInClasspath(String classPath) {\n        if (classPath == null) {\n            return null;\n        }\n\n        for (String entry : classPath.split(File.pathSeparator)) {\n            File file = new File(entry);\n            if (isMaskedJar(file)) {\n                return file;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Finds a masked JAR file in the given classpath entries.\n     * A masked JAR is identified by containing META-INF/btrace/shared/ directory.\n     *\n     * @param cpEntries the classpath entries array\n     * @return the masked JAR file, or null if not found\n     */\n    public static File findMaskedJarInClasspath(String[] cpEntries) {\n        if (cpEntries == null) {\n            return null;\n        }\n\n        for (String entry : cpEntries) {\n            File file = new File(entry);\n            if (isMaskedJar(file)) {\n                return file;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Checks if the given file is a masked JAR.\n     * A masked JAR is identified by containing META-INF/btrace/shared/ directory.\n     *\n     * @param file the file to check\n     * @return true if the file is a masked JAR, false otherwise\n     */\n    public static boolean isMaskedJar(File file) {\n        if (file == null || !file.exists() || !file.isFile() || !file.getName().endsWith(\".jar\")) {\n            return false;\n        }\n\n        try (JarFile jar = new JarFile(file)) {\n            // Look for the shared section marker\n            return jar.getEntry(\"META-INF/btrace/shared/\") != null;\n        } catch (IOException e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-bootstrap/build.gradle",
    "content": "plugins {\n    id 'java-library'\n    alias(libs.plugins.shadow)\n}\n\ndef bootIncludes = {\n    if (it.directory) {\n        return true\n    }\n    if (it.path.endsWith('.jar')) {\n        return true\n    }\n    if (it.path.startsWith('org/openjdk/btrace/core/')) {\n        if (it.path == 'org/openjdk/btrace/core/Messages.class'\n                || it.path == 'org/openjdk/btrace/core/messages.properties') {\n            return false\n        }\n        if (it.path.startsWith('org/openjdk/btrace/core/extensions/')) {\n            return false\n        }\n        // Include handlers - probe classes need them in their static initializers\n        if (it.path.startsWith('org/openjdk/btrace/core/handlers/')) {\n            return true\n        }\n        if (it.path.startsWith('org/openjdk/btrace/core/comm/')) {\n            return false\n        }\n        // Include annotations - needed by compiler at compile-time\n        if (it.path.startsWith('org/openjdk/btrace/core/annotations/')) {\n            return true\n        }\n        return true\n    }\n    if (it.path.startsWith('META-INF/services')) {\n        return !it.path.contains('com.sun.') && !it.path.contains('javax.annotation.')\n    }\n    // Include BTraceRuntimeAccess and LinkingFlag from btrace-core (bootstrap classes)\n    if (it.path.startsWith('org/openjdk/btrace/runtime/')) {\n        // Match BTraceRuntimeAccess but NOT BTraceRuntimeAccessImpl\n        if (it.path.startsWith('org/openjdk/btrace/runtime/BTraceRuntimeAccess.class')\n                || it.path.startsWith('org/openjdk/btrace/runtime/BTraceRuntimeAccess$')\n                || it.path.startsWith('org/openjdk/btrace/runtime/LinkingFlag')) {\n            return true\n        }\n        // Include invokedynamic bootstrap classes (they use volatile fields to reach agent implementations)\n        if (it.path.startsWith('org/openjdk/btrace/runtime/Indy')\n                || it.path.startsWith('org/openjdk/btrace/runtime/ExtensionIndy')) {\n            return true\n        }\n        // Include Auxiliary class - probe classes are defined via MethodHandles.privateLookupIn(Auxiliary.class)\n        // and must be bootstrap-visible so they're accessible from application classloaders\n        if (it.path.startsWith('org/openjdk/btrace/runtime/auxiliary/Auxiliary')) {\n            return true\n        }\n        return false\n    }\n    // Include ExtensionBridge interface (referenced by ExtensionIndy)\n    if (it.path == 'org/openjdk/btrace/extension/ExtensionBridge.class') {\n        return true\n    }\n    // Include slf4j for bootstrap classes (DebugSupport needs it)\n    if (it.path.startsWith('org/slf4j/')) {\n        return true\n    }\n    return false\n}\n\ndependencies {\n    implementation project(':btrace-core')\n    implementation project(':btrace-runtime')\n    implementation project(':btrace-instr')\n    implementation project(':btrace-extension')\n}\n\njar {\n    enabled = false\n}\n\nshadowJar {\n    archiveBaseName.set('btrace-bootstrap')\n    archiveVersion.set('')\n    archiveClassifier.set('')\n\n    include bootIncludes\n\n    configurations = [project.configurations.runtimeClasspath]\n    relocate 'org.jctools', 'org.openjdk.btrace.libs.boot.org.jctools'\n    relocate 'org.objectweb.asm', 'org.openjdk.btrace.libs.org.objectweb.asm'\n    relocate 'org.slf4j', 'org.openjdk.btrace.libs.org.slf4j'\n}\n\nassemble.dependsOn shadowJar\n"
  },
  {
    "path": "btrace-client/build.gradle",
    "content": "import java.text.SimpleDateFormat\nimport java.util.Date\n\nbuildscript { scriptHandler ->\n    apply from: rootProject.file('buildSrc/shared.gradle'), to: scriptHandler\n}\n\ndependencies {\n    implementation libs.slf4j\n    implementation libs.asm\n    implementation libs.asm.tree\n    implementation libs.asm.util\n\n    def toolsJar = getToolsJar();\n    if (toolsJar.getAsFile().exists()) {\n        runtimeOnly files(\"${toolsJar}\")\n    }\n\n    implementation project(':btrace-core')\n    implementation project(':btrace-compiler')\n    implementation project(':btrace-instr')\n    implementation project(':btrace-boot')\n}\n\njar {\n    manifest {\n        attributes(\n                'Built-By'       : System.properties['user.name'],\n                'Build-Timestamp': new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss.SSSZ\").format(new Date()),\n                'Build-Revision' : getGitCommit(),\n                'Created-By'     : \"Gradle ${gradle.gradleVersion}\",\n                'Build-Jdk'      : \"${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']})\",\n                'Build-OS'       : \"${System.properties['os.name']} ${System.properties['os.arch']} ${System.properties['os.version']}\",\n                'Main-Class'     : \"org.openjdk.btrace.client.Main\"\n        )\n    }\n}\n"
  },
  {
    "path": "btrace-client/src/main/java/org/openjdk/btrace/client/Client.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.client;\n\nimport com.sun.tools.attach.AgentLoadException;\nimport com.sun.tools.attach.VirtualMachine;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.PrintWriter;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.net.ConnectException;\nimport java.net.Socket;\nimport java.net.URI;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.net.UnknownHostException;\nimport java.nio.file.Files;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport org.objectweb.asm.AnnotationVisitor;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\nimport org.openjdk.btrace.boot.MaskedClassLoader;\nimport org.openjdk.btrace.boot.MaskedJarUtils;\nimport org.openjdk.btrace.compiler.Compiler;\nimport org.openjdk.btrace.core.Args;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.core.annotations.DTrace;\nimport org.openjdk.btrace.core.annotations.DTraceRef;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.openjdk.btrace.core.comm.DisconnectCommand;\nimport org.openjdk.btrace.core.comm.EventCommand;\nimport org.openjdk.btrace.core.comm.ExitCommand;\nimport org.openjdk.btrace.core.comm.InstrumentCommand;\nimport org.openjdk.btrace.core.comm.BinaryWireProtocol;\nimport org.openjdk.btrace.core.comm.JavaSerializationProtocol;\nimport org.openjdk.btrace.core.comm.ListFailedExtensionsCommand;\nimport org.openjdk.btrace.core.comm.ListProbesCommand;\nimport org.openjdk.btrace.core.comm.MessageCommand;\nimport org.openjdk.btrace.core.comm.ReconnectCommand;\nimport org.openjdk.btrace.core.comm.SetSettingsCommand;\nimport org.openjdk.btrace.core.comm.StatusCommand;\nimport org.openjdk.btrace.core.comm.ProtocolConfig;\nimport org.openjdk.btrace.core.comm.ProtocolNegotiator;\nimport org.openjdk.btrace.core.comm.ProtocolVersion;\nimport org.openjdk.btrace.core.comm.WireProtocol;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class represents a BTrace client. This can be used to create command line as well as a GUI\n * based BTrace clients. The BTrace compilation, traced JVM attach, submission of compiled program\n * and and I/O to the traced JVM are handled by this class.\n *\n * @author A. Sundararajan\n */\npublic class Client {\n  private static final Logger log = LoggerFactory.getLogger(Client.class);\n\n  private static final String DTRACE_DESC;\n  private static final String DTRACE_REF_DESC;\n  private static boolean dtraceEnabled;\n  private static Method submitFile;\n  private static Method submitString;\n\n  static {\n    try {\n      /*\n       * Check for DTrace Consumer class -- if we don't have that\n       * either /usr/lib/share/java/dtrace.jar is not in CLASSPATH\n       * or we are not running on Solaris 11+.\n       */\n      Class<?> dtraceConsumerClass = Class.forName(\"org.opensolaris.os.dtrace.Consumer\");\n      /*\n       * Check for BTrace's DTrace support class -- if that is available\n       * may be the user didn't build BTrace on Solaris 11. S/he built\n       * it on Solaris 10 or below or some other OS.\n       */\n      Class<?> dtraceClass = Class.forName(\"com.sun.btrace.dtrace.DTrace\");\n      dtraceEnabled = true;\n      submitFile =\n          dtraceClass.getMethod(\"submit\", File.class, String[].class, CommandListener.class);\n      submitString =\n          dtraceClass.getMethod(\"submit\", String.class, String[].class, CommandListener.class);\n    } catch (Exception exp) {\n      dtraceEnabled = false;\n    }\n    DTRACE_DESC = Type.getDescriptor(DTrace.class);\n    DTRACE_REF_DESC = Type.getDescriptor(DTraceRef.class);\n  }\n\n  // port on which BTrace agent listens\n  private final int port;\n  // the output file or null\n  private final String outputFile;\n  // are we running debug mode?\n  private final boolean debug;\n  // do we need to track retransforming single classes? (will impose additional overhead)\n  private final boolean trackRetransforms;\n  // are we running in trusted mode?\n  private final boolean trusted;\n  // are we dumping .class files of\n  // the instrumented classes?\n  private final boolean dumpClasses;\n  // which directory we dump the .class files?\n  private final String dumpDir;\n  private final String probeDescPath;\n  private final String statsdDef;\n  // override paths for agent and boot JARs (for jbang support)\n  private final String agentJarOverride;\n  private final String bootJarOverride;\n\n  // connection state to the traced JVM\n  private volatile Socket sock;\n  private volatile WireProtocol protocol;\n\n  private boolean disconnected = false;\n\n  public Client(int port) {\n    this(port, null, \".\", false, false, false, false, null, null, null, null);\n  }\n\n  public Client(int port, String probeDescPath) {\n    this(port, null, probeDescPath, false, false, false, false, null, null, null, null);\n  }\n\n  public Client(\n      int port,\n      String outputFile,\n      String probeDescPath,\n      boolean debug,\n      boolean trackRetransforms,\n      boolean trusted,\n      boolean dumpClasses,\n      String dumpDir,\n      String statsdDef) {\n    this(\n        port,\n        outputFile,\n        probeDescPath,\n        debug,\n        trackRetransforms,\n        trusted,\n        dumpClasses,\n        dumpDir,\n        statsdDef,\n        null,\n        null);\n  }\n\n  public Client(\n      int port,\n      String outputFile,\n      String probeDescPath,\n      boolean debug,\n      boolean trackRetransforms,\n      boolean trusted,\n      boolean dumpClasses,\n      String dumpDir,\n      String statsdDef,\n      String agentJarOverride,\n      String bootJarOverride) {\n    this.port = port;\n    this.outputFile = outputFile;\n    this.probeDescPath = probeDescPath;\n    this.debug = debug;\n    this.trusted = trusted;\n    this.dumpClasses = dumpClasses;\n    this.dumpDir = dumpDir;\n    this.trackRetransforms = trackRetransforms;\n    this.statsdDef = statsdDef;\n    this.agentJarOverride = agentJarOverride;\n    this.bootJarOverride = bootJarOverride;\n  }\n\n  private static boolean isPortAvailable(int port) {\n    Socket clSocket = null;\n    try {\n      clSocket = new Socket(\"127.0.0.1\", port);\n    } catch (IOException ignored) {\n      // ignore\n    }\n    if (clSocket != null) {\n      try {\n        clSocket.close();\n      } catch (IOException ignored) {\n        // ignore\n      }\n      return false;\n    }\n    return true;\n  }\n\n  private boolean isAgentAvailableAfterLoadFailure(VirtualMachine vm) {\n    try {\n      Properties serverVmProps = vm.getSystemProperties();\n      String serverPort = serverVmProps.getProperty(\"btrace.port\");\n      if (serverPort != null) {\n        return Integer.parseInt(serverPort) == port;\n      }\n    } catch (Exception ignore) {\n      // fall through to port probe\n    }\n    return !isPortAvailable(port);\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  public byte[] compile(String fileName, String classPath) {\n    return compile(fileName, classPath, new PrintWriter(System.err), null);\n  }\n\n  /** Compiles given BTrace program using given classpath. */\n  @SuppressWarnings(\"DefaultCharset\")\n  public byte[] compile(String fileName, String classPath, String includePath) {\n    return compile(fileName, classPath, new PrintWriter(System.err), includePath);\n  }\n\n  public byte[] compile(String fileName, String classPath, PrintWriter err) {\n    return compile(fileName, classPath, err, null);\n  }\n\n  /**\n   * Scans the extensions directory and returns a classpath string with all API JARs.\n   *\n   * Looks in the following locations (first match wins):\n   * - System property 'btrace.libs' (assumed to point to BTrace libs directory); scans sibling 'extensions/'\n   * - Derived from java.class.path entry containing 'btrace-client' (for dist layouts); scans sibling 'extensions/'\n   */\n  private String getExtensionApiClasspath() {\n    try {\n      // 1) Use -Dbtrace.libs if provided\n      String libsProp = System.getProperty(\"btrace.libs\");\n      if (libsProp != null && !libsProp.isEmpty()) {\n        File libsDir = new File(libsProp);\n        File btraceHome = libsDir.getParentFile();\n        String cp = scanExtensionsDir(new File(btraceHome, \"extensions\"));\n        if (!cp.isEmpty()) {\n          return cp;\n        }\n      }\n\n      // 2) Fall back to locating btrace-client in the classpath\n      String classPath = System.getProperty(\"java.class.path\");\n      for (String entry : classPath.split(File.pathSeparator)) {\n        if (entry.contains(\"btrace-client\")) {\n          File clientPath = new File(entry);\n          File libsDir = clientPath.getParentFile();\n          if (libsDir != null) {\n            File btraceHome = libsDir.getParentFile();\n            String cp = scanExtensionsDir(new File(btraceHome, \"extensions\"));\n            if (!cp.isEmpty()) {\n              return cp;\n            }\n          }\n        }\n      }\n    } catch (Exception e) {\n      log.warn(\"Failed to scan extensions directory\", e);\n    }\n    return \"\";\n  }\n\n  /**\n   * Builds a classpath string of all *-api.jar files in immediate subdirectories of the given\n   * extensions directory.\n   */\n  private static String scanExtensionsDir(File extensionsDir) {\n    if (extensionsDir == null || !extensionsDir.exists() || !extensionsDir.isDirectory()) {\n      return \"\";\n    }\n    StringBuilder cp = new StringBuilder();\n    File[] extensionDirs = extensionsDir.listFiles(File::isDirectory);\n    if (extensionDirs != null) {\n      for (File extDir : extensionDirs) {\n        File[] apiJars = extDir.listFiles((dir, name) -> name.endsWith(\"-api.jar\"));\n        if (apiJars != null) {\n          for (File jar : apiJars) {\n            if (cp.length() > 0) {\n              cp.append(File.pathSeparator);\n            }\n            cp.append(jar.getAbsolutePath());\n          }\n        }\n      }\n    }\n    return cp.toString();\n  }\n\n  private WireProtocol createProtocol(Socket socket, String host, boolean allowFallback)\n      throws IOException {\n    ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n    ProtocolVersion preferred = config.getVersion();\n\n    if (config.isAutoNegotiate() && preferred == ProtocolVersion.V2) {\n      try {\n        return createV2Protocol(socket);\n      } catch (IOException e) {\n        if (!allowFallback) {\n          throw e;\n        }\n        closeSocketQuietly(socket);\n        Socket fallback = new Socket(host, port);\n        this.sock = fallback;\n        return createV1Protocol(fallback);\n      }\n    }\n\n    if (config.isForceVersion() && preferred == ProtocolVersion.V2) {\n      return createV2Protocol(socket);\n    }\n\n    return createV1Protocol(socket);\n  }\n\n  private WireProtocol createV1Protocol(Socket socket) throws IOException {\n    InputStream in = socket.getInputStream();\n    OutputStream out = socket.getOutputStream();\n    return new JavaSerializationProtocol(in, out);\n  }\n\n  private WireProtocol createV2Protocol(Socket socket) throws IOException {\n    InputStream in = socket.getInputStream();\n    OutputStream out = socket.getOutputStream();\n    ProtocolNegotiator negotiator = new ProtocolNegotiator(ProtocolVersion.V2);\n    int timeoutMs = ProtocolNegotiator.getNegotiationTimeoutMs();\n    int previousTimeout = socket.getSoTimeout();\n    try {\n      socket.setSoTimeout(timeoutMs);\n      ProtocolVersion negotiated = negotiator.negotiateClient(in, out, ProtocolVersion.V2);\n      if (negotiated != ProtocolVersion.V2) {\n        throw new IOException(\"Protocol negotiation failed: expected V2\");\n      }\n      return new BinaryWireProtocol(in, out);\n    } finally {\n      socket.setSoTimeout(previousTimeout);\n    }\n  }\n\n  private void closeSocketQuietly(Socket socket) {\n    if (socket == null) {\n      return;\n    }\n    try {\n      socket.close();\n    } catch (IOException ignore) {\n    }\n  }\n\n  /**\n   * Compiles given BTrace program using given classpath. Errors and warning are written to given\n   * PrintWriter.\n   */\n  public byte[] compile(String fileName, String classPath, PrintWriter err, String includePath) {\n    File file = new File(fileName);\n    if (fileName.endsWith(\".java\")) {\n      Compiler compiler = new Compiler(includePath);\n      classPath += File.pathSeparator + System.getProperty(\"java.class.path\");\n      // Add extension API JARs to classpath\n      String extApiCp = getExtensionApiClasspath();\n      if (!extApiCp.isEmpty()) {\n        classPath += File.pathSeparator + extApiCp;\n      }\n      if (log.isDebugEnabled()) {\n        log.debug(\"compiling {}\", fileName);\n        if (!extApiCp.isEmpty()) {\n          log.debug(\"extension API classpath: {}\", extApiCp);\n        }\n        log.debug(\"compiler classpath: {}\", classPath);\n      }\n\n      // Ensure the verifier's classloader can see the same classpath (TCCL lookup)\n      ClassLoader prevCl = Thread.currentThread().getContextClassLoader();\n      String prevSysCp = System.getProperty(\"java.class.path\", \"\");\n      Map<String, byte[]> classes;\n      try {\n        String[] cpEntries = classPath.split(File.pathSeparator);\n\n        // Check if any entry is a masked JAR (contains META-INF/btrace/shared/)\n        File maskedJar = MaskedJarUtils.findMaskedJarInClasspath(cpEntries);\n        ClassLoader compileCl;\n\n        if (maskedJar != null) {\n          // Use MaskedClassLoader to load classes from .classdata files\n          log.debug(\"Using MaskedClassLoader for compilation: {}\", maskedJar.getAbsolutePath());\n          compileCl = new MaskedClassLoader(maskedJar, \"client\", prevCl);\n        } else {\n          // Fall back to URLClassLoader for standard JARs\n          java.net.URL[] urls = new java.net.URL[cpEntries.length];\n          for (int i = 0; i < cpEntries.length; i++) {\n            urls[i] = new File(cpEntries[i]).toURI().toURL();\n          }\n          compileCl = new java.net.URLClassLoader(urls, prevCl);\n        }\n\n        Thread.currentThread().setContextClassLoader(compileCl);\n        // Ensure VerifierVisitor fallback scan (java.class.path) can see extension API jars\n        if (!extApiCp.isEmpty()) {\n          System.setProperty(\n              \"java.class.path\",\n              prevSysCp.isEmpty() ? extApiCp : (prevSysCp + File.pathSeparator + extApiCp));\n        }\n        classes = compiler.compile(file, err, \".\", classPath);\n      } catch (Exception e) {\n        log.error(\"Failed to set up compiler classloader\", e);\n        classes = compiler.compile(file, err, \".\", classPath);\n      } finally {\n        Thread.currentThread().setContextClassLoader(prevCl);\n        System.setProperty(\"java.class.path\", prevSysCp);\n      }\n      if (classes == null) {\n        log.error(\"btrace compilation for script {} failed!\", fileName);\n        return null;\n      }\n\n      int size = classes.size();\n      if (size != 1) {\n        log.error(\"no classes or more than one class in script {}\", fileName);\n        return null;\n      }\n      String name = classes.keySet().iterator().next();\n      byte[] code = classes.get(name);\n      if (log.isDebugEnabled()) {\n        log.debug(\"compiled {}\", fileName);\n      }\n      return code;\n    } else if (fileName.endsWith(\".class\")) {\n      int codeLen = (int) file.length();\n      byte[] code = new byte[codeLen];\n      try {\n        if (log.isDebugEnabled()) {\n          log.debug(\"reading {}\", fileName);\n        }\n        try (FileInputStream fis = new FileInputStream(file)) {\n          int off = 0;\n          int len = 0;\n          do {\n            len = fis.read(code, off, codeLen - off);\n            if (len > -1) {\n              off += len;\n            }\n          } while (off < codeLen && len != -1);\n        }\n        if (log.isDebugEnabled()) {\n          log.debug(\"read {}\", fileName);\n        }\n        return code;\n      } catch (IOException exp) {\n        err.println(exp.getMessage());\n        return null;\n      }\n    } else {\n      err.println(\"BTrace script has to be a .java or a .class\");\n      return null;\n    }\n  }\n\n  public byte[] compileSource(String fileName, String source, String classPath) {\n    return compileSource(fileName, source, classPath, new PrintWriter(System.err), null);\n  }\n\n  public byte[] compileSource(\n      String fileName, String source, String classPath, PrintWriter err, String includePath) {\n    return compileInternal(\n        fileName,\n        classPath,\n        err,\n        includePath,\n        (compiler, resolvedCp) -> compiler.compile(fileName, source, err, \".\", resolvedCp));\n  }\n\n  @FunctionalInterface\n  private interface CompilerInvoker {\n    Map<String, byte[]> compile(Compiler compiler, String classPath) throws Exception;\n  }\n\n  private byte[] compileInternal(\n      String scriptName,\n      String classPath,\n      PrintWriter err,\n      String includePath,\n      CompilerInvoker invoker) {\n    Compiler compiler = new Compiler(includePath);\n    classPath += File.pathSeparator + System.getProperty(\"java.class.path\");\n    // Add extension API JARs to classpath\n    String extApiCp = getExtensionApiClasspath();\n    if (!extApiCp.isEmpty()) {\n      classPath += File.pathSeparator + extApiCp;\n    }\n    if (log.isDebugEnabled()) {\n      log.debug(\"compiling {}\", scriptName);\n      if (!extApiCp.isEmpty()) {\n        log.debug(\"extension API classpath: {}\", extApiCp);\n      }\n      log.debug(\"compiler classpath: {}\", classPath);\n    }\n\n    // Ensure the verifier's classloader can see the same classpath (TCCL lookup)\n    ClassLoader prevCl = Thread.currentThread().getContextClassLoader();\n    String prevSysCp = System.getProperty(\"java.class.path\", \"\");\n    Map<String, byte[]> classes;\n    try {\n      String[] cpEntries = classPath.split(File.pathSeparator);\n      URL[] urls = new URL[cpEntries.length];\n      for (int i = 0; i < cpEntries.length; i++) {\n        urls[i] = new File(cpEntries[i]).toURI().toURL();\n      }\n      URLClassLoader compileCl = new URLClassLoader(urls, prevCl);\n      Thread.currentThread().setContextClassLoader(compileCl);\n      // Ensure VerifierVisitor fallback scan (java.class.path) can see extension API jars\n      if (!extApiCp.isEmpty()) {\n        System.setProperty(\n            \"java.class.path\",\n            prevSysCp.isEmpty() ? extApiCp : (prevSysCp + File.pathSeparator + extApiCp));\n      }\n      classes = invoker.compile(compiler, classPath);\n    } catch (Exception e) {\n      log.error(\"Failed to set up compiler classloader\", e);\n      try {\n        classes = invoker.compile(compiler, classPath);\n      } catch (Exception ex) {\n        log.error(\"btrace compilation for script {} failed!\", scriptName, ex);\n        return null;\n      }\n    } finally {\n      Thread.currentThread().setContextClassLoader(prevCl);\n      System.setProperty(\"java.class.path\", prevSysCp);\n    }\n    if (classes == null) {\n      log.error(\"btrace compilation for script {} failed!\", scriptName);\n      return null;\n    }\n\n    int size = classes.size();\n    if (size != 1) {\n      log.error(\"no classes or more than one class in script {}\", scriptName);\n      return null;\n    }\n    String name = classes.keySet().iterator().next();\n    byte[] code = classes.get(name);\n    if (log.isDebugEnabled()) {\n      log.debug(\"compiled {}\", scriptName);\n    }\n    return code;\n  }\n\n  /**\n   * Attach the BTrace client to the given Java process. Loads BTrace agent on the target process if\n   * not loaded already.\n   */\n  public void attach(String pid, String sysCp, String bootCp) throws IOException {\n    try {\n      String agentPath;\n      boolean isMaskedJar = false;\n\n      // If --agent-jar was specified, use it\n      if (agentJarOverride != null && !agentJarOverride.isEmpty()) {\n        File agentFile = new File(agentJarOverride);\n        if (!agentFile.exists()) {\n          throw new IOException(\"Specified agent JAR does not exist: \" + agentJarOverride);\n        }\n        agentPath = agentFile.getAbsolutePath();\n        isMaskedJar = isMaskedJar(agentFile);\n      } else {\n        // Find masked btrace.jar in classpath\n        agentPath = findMaskedAgentJar();\n        if (agentPath == null) {\n          throw new IOException(\"No masked btrace.jar found in classpath. \" +\n              \"Please ensure btrace.jar (not btrace-client.jar) is in the classpath.\");\n        }\n        // Verify it exists and is readable\n        File agentFile = new File(agentPath);\n        if (!agentFile.exists() || !agentFile.canRead()) {\n          throw new IOException(\"Agent JAR not found or not readable: \" + agentPath);\n        }\n        agentPath = agentFile.getAbsolutePath();  // Normalize to absolute path\n        isMaskedJar = true;  // findMaskedAgentJar only returns masked JARs\n      }\n\n      // Handle boot classpath for masked JAR\n      String effectiveBootCp = bootCp;\n\n      // For masked JAR, use the agent JAR itself as boot classpath (it has bootstrap classes as .class files)\n      if (isMaskedJar) {\n        if (bootCp == null || bootCp.isEmpty() || bootCp.equals(\".\")) {\n          effectiveBootCp = agentPath;\n        } else {\n          // If bootCp is set to something else, prepend the masked JAR to it\n          effectiveBootCp = agentPath + File.pathSeparator + bootCp;\n        }\n      }\n\n      attach(pid, agentPath, sysCp, effectiveBootCp);\n    } catch (RuntimeException | IOException e) {\n      throw e;\n    } catch (Exception exp) {\n      throw new IOException(\"Failed to attach to PID \" + pid, exp);\n    }\n  }\n\n  /**\n   * Attach the BTrace client to the given Java process. Loads BTrace agent on the target process if\n   * not loaded already. Accepts the full path of the btrace agent jar. Also, accepts system\n   * classpath and boot classpath optionally.\n   */\n  public void attach(String pid, String agentPath, String sysCp, String bootCp) throws IOException {\n    try {\n      VirtualMachine vm = null;\n      if (log.isDebugEnabled()) {\n        log.debug(\"attaching to {}\", pid);\n      }\n      vm = VirtualMachine.attach(pid);\n      if (log.isDebugEnabled()) {\n        log.debug(\"checking port availability: {}\", port);\n      }\n      Properties serverVmProps = vm.getSystemProperties();\n      int serverPort = Integer.parseInt(serverVmProps.getProperty(\"btrace.port\", \"-1\"));\n      if (serverPort != -1) {\n        if (serverPort != port) {\n          throw new IOException(\n              \"Can not attach to PID \"\n                  + pid\n                  + \" on port \"\n                  + port\n                  + \". There is already a BTrace server active on port \"\n                  + serverPort\n                  + \"!\");\n        }\n      } else {\n        if (!isPortAvailable(port)) {\n          throw new IOException(\"Port \" + port + \" unavailable.\");\n        }\n      }\n\n      if (log.isDebugEnabled()) {\n        log.debug(\"attached to {}\", pid);\n        log.debug(\"loading {}\", agentPath);\n      }\n      String agentArgs = Args.PORT + \"=\" + port;\n      if (statsdDef != null) {\n        agentArgs += \",\" + Args.STATSD + \"=\" + statsdDef;\n      }\n      if (debug) {\n        agentArgs += \",\" + Args.DEBUG + \"=true\";\n      }\n      if (trusted) {\n        agentArgs += \",\" + Args.TRUSTED + \"=true\";\n      }\n      if (dumpClasses) {\n        agentArgs += \",\" + Args.DUMP_CLASSES + \"=true\";\n        agentArgs += \",\" + Args.DUMP_DIR + \"=\" + dumpDir;\n      }\n      if (trackRetransforms) {\n        agentArgs += \",\" + Args.TRACK_RETRANSFORMS + \"=true\";\n      }\n      if (bootCp != null) {\n        agentArgs += \",\" + Args.BOOT_CLASS_PATH + \"=\" + bootCp;\n      }\n      String toolsPath =\n          getToolsJarPath(\n              serverVmProps.getProperty(\"java.class.path\"), serverVmProps.getProperty(\"java.home\"));\n      if (sysCp == null) {\n        sysCp = toolsPath;\n      } else {\n        sysCp = sysCp + File.pathSeparator + toolsPath;\n      }\n      agentArgs += \",\" + Args.SYSTEM_CLASS_PATH + \"=\" + sysCp;\n      String cmdQueueLimit = System.getProperty(BTraceRuntime.CMD_QUEUE_LIMIT_KEY, null);\n      if (cmdQueueLimit != null) {\n        agentArgs += \",=\" + Args.CMD_QUEUE_LIMIT + cmdQueueLimit;\n      }\n      agentArgs += \",\" + Args.PROBE_DESC_PATH + \"=\" + probeDescPath;\n      if (log.isDebugEnabled()) {\n        log.debug(\"agent args: {}\", agentArgs);\n      }\n      boolean isJava8 = serverVmProps.getProperty(\"java.version\", \"\").startsWith(\"1.8\");\n      // HotSpot on JDK 8 can report AgentLoadException(\"0\") even when the agent loads successfully.\n      // Use a small retry window and treat error code 0 as success only if the agent is reachable.\n      int attempts = isJava8 ? 3 : 1;\n      AgentLoadException lastAle = null;\n      for (int i = 0; i < attempts; i++) {\n        try {\n          vm.loadAgent(agentPath, agentArgs);\n          lastAle = null;\n          break;\n        } catch (AgentLoadException ale) {\n          lastAle = ale;\n          if (isJava8 && ale.getMessage() != null && ale.getMessage().endsWith(\"0\")) {\n            if (isAgentAvailableAfterLoadFailure(vm)) {\n              if (log.isDebugEnabled()) {\n                log.debug(\"Agent load reported error 0 but agent is available on port {}\", port);\n              }\n              lastAle = null;\n              break;\n            }\n            try {\n              Thread.sleep(100);\n            } catch (InterruptedException ie) {\n              Thread.currentThread().interrupt();\n              break;\n            }\n            continue;\n          }\n          throw ale;\n        }\n      }\n      if (lastAle != null) {\n        throw lastAle;\n      }\n      if (log.isDebugEnabled()) {\n        log.debug(\"loaded {}\", agentPath);\n      }\n    } catch (RuntimeException | IOException re) {\n      System.err.println(\"[DEBUG] IOException/RuntimeException during attach:\");\n      re.printStackTrace();\n      throw re;\n    } catch (Exception exp) {\n      System.err.println(\"[DEBUG] Exception during attach:\");\n      exp.printStackTrace();\n      throw new IOException(\"Failed to attach to PID \" + pid, exp);\n    }\n  }\n\n  void connectAndListProbes(String host, CommandListener listener) throws IOException {\n    if (sock != null) {\n      throw new IllegalStateException();\n    }\n    try {\n      if (log.isDebugEnabled()) {\n        log.debug(\"opening socket to {}\", port);\n      }\n      long timeout = System.nanoTime() + TimeUnit.NANOSECONDS.convert(5, TimeUnit.SECONDS);\n      while (sock == null && System.nanoTime() <= timeout) {\n        try {\n          sock = new Socket(host, port);\n        } catch (ConnectException e) {\n          log.debug(\"server not yet available; retrying ...\");\n          Thread.sleep(20);\n        }\n      }\n\n      if (sock == null) {\n        log.debug(\"server not available. exiting.\");\n        System.exit(1);\n      }\n      protocol = createProtocol(sock, host, true);\n      protocol.write(new ListProbesCommand());\n\n      log.debug(\"entering into command loop\");\n      commandLoop(\n          cmd -> {\n            if (cmd.getType() == Command.LIST_PROBES) {\n              listener.onCommand(cmd);\n              System.exit(0);\n            } else {\n              listener.onCommand(cmd);\n            }\n          });\n    } catch (UnknownHostException uhe) {\n      throw new IOException(uhe);\n    } catch (InterruptedException e) {\n      Thread.currentThread().interrupt();\n    }\n  }\n\n  void connectAndListFailedExtensions(String host, CommandListener listener) throws IOException {\n    if (sock != null) {\n      throw new IllegalStateException();\n    }\n    try {\n      if (log.isDebugEnabled()) {\n        log.debug(\"opening socket to {}\", port);\n      }\n      long timeout = System.nanoTime() + TimeUnit.NANOSECONDS.convert(5, TimeUnit.SECONDS);\n      while (sock == null && System.nanoTime() <= timeout) {\n        try {\n          sock = new Socket(host, port);\n        } catch (ConnectException e) {\n          log.debug(\"server not yet available; retrying ...\");\n          Thread.sleep(20);\n        }\n      }\n\n      if (sock == null) {\n        log.debug(\"server not available. exiting.\");\n        System.exit(1);\n      }\n      protocol = createProtocol(sock, host, true);\n      protocol.write(new ListFailedExtensionsCommand());\n\n      log.debug(\"entering into command loop\");\n      commandLoop(\n          cmd -> {\n            if (cmd.getType() == Command.LIST_FAILED_EXTENSIONS) {\n              listener.onCommand(cmd);\n              System.exit(0);\n            } else {\n              listener.onCommand(cmd);\n            }\n          });\n    } catch (UnknownHostException uhe) {\n      throw new IOException(uhe);\n    } catch (InterruptedException e) {\n      Thread.currentThread().interrupt();\n    }\n  }\n\n  void reconnect(String host, String resumeProbe, CommandListener listener, String[] command)\n      throws IOException {\n    if (sock != null) {\n      throw new IllegalStateException();\n    }\n    try {\n      if (log.isDebugEnabled()) {\n        log.debug(\"opening socket to {}\", port);\n      }\n      long timeout = System.nanoTime() + TimeUnit.NANOSECONDS.convert(5, TimeUnit.SECONDS);\n      while (sock == null && System.nanoTime() <= timeout) {\n        try {\n          sock = new Socket(host, port);\n        } catch (ConnectException e) {\n          log.debug(\"server not yet available; retrying ...\");\n          Thread.sleep(20);\n        }\n      }\n\n      if (sock == null) {\n        log.debug(\"server not available. exiting.\");\n        System.exit(1);\n      }\n      protocol = createProtocol(sock, host, true);\n\n      log.debug(\"reconnecting client {}\", resumeProbe);\n      protocol.write(new ReconnectCommand(resumeProbe));\n\n      log.debug(\"entering into command loop\");\n      commandLoop(\n          new CommandListener() {\n            boolean statusReported = false;\n\n            @Override\n            public void onCommand(Command cmd) throws IOException {\n              if (statusReported || cmd.getType() != Command.STATUS) {\n                listener.onCommand(cmd);\n              } else {\n                StatusCommand statusCommand = (StatusCommand) cmd;\n                if (statusCommand.getFlag() == ReconnectCommand.STATUS_FLAG) {\n                  if (statusCommand.isSuccess()) {\n                    log.info(\"Reconnected to an active probe: {}\", resumeProbe);\n                    String probeCommand = command[0];\n                    String probeCommandArg = command[1];\n                    if (probeCommand != null) {\n                      if (log.isDebugEnabled()) {\n                        log.debug(\n                            \"Executing remote command '{}'{}\",\n                            probeCommand,\n                            (probeCommandArg != null ? \"(\" + probeCommandArg + \")\" : \"\"));\n                      }\n                      switch (probeCommand) {\n                        case \"exit\":\n                          {\n                            sendExit();\n                            break;\n                          }\n                        case \"event\":\n                          {\n                            if (probeCommandArg == null || probeCommandArg.equals(\"*\")) {\n                              sendEvent();\n                            } else {\n                              sendEvent(probeCommandArg);\n                            }\n                            sendDisconnect();\n                            break;\n                          }\n                        default:\n                          {\n                            log.warn(\"Unrecognized BTrace command {}\", probeCommand);\n                          }\n                      }\n                    }\n                  } else {\n                    log.warn(\"Unable to reconnect to an active probe: {}\", resumeProbe);\n                    System.exit(1);\n                  }\n                } else {\n                  listener.onCommand(cmd);\n                }\n                statusReported = true;\n              }\n            }\n          });\n    } catch (UnknownHostException uhe) {\n      throw new IOException(uhe);\n    } catch (InterruptedException e) {\n      Thread.currentThread().interrupt();\n    }\n  }\n\n  /**\n   * Submits the compiled BTrace .class to the VM attached and passes given command line arguments.\n   * Receives commands from the traced JVM and sends those to the command listener provided.\n   */\n  public void submit(String fileName, byte[] code, String[] args, CommandListener listener)\n      throws IOException {\n    submit(\"localhost\", fileName, code, args, listener);\n  }\n\n  /**\n   * Submits the compiled BTrace .class to the VM attached and passes given command line arguments.\n   * Receives commands from the traced JVM and sends those to the command listener provided.\n   */\n  public void submit(\n      String host, String fileName, byte[] code, String[] args, CommandListener listener)\n      throws IOException {\n    if (sock != null) {\n      throw new IllegalStateException();\n    }\n    submitDTrace(fileName, code, args, listener);\n    try {\n      if (log.isDebugEnabled()) {\n        log.debug(\"opening socket to {}\", port);\n      }\n      long timeout = System.nanoTime() + TimeUnit.NANOSECONDS.convert(5, TimeUnit.SECONDS);\n      while (sock == null && System.nanoTime() <= timeout) {\n        try {\n          sock = new Socket(host, port);\n        } catch (ConnectException e) {\n          log.debug(\"server not yet available; retrying ...\");\n          Thread.sleep(20);\n        }\n      }\n\n      if (sock == null) {\n        log.debug(\"server not available. exiting.\");\n        System.exit(1);\n      }\n      protocol = createProtocol(sock, host, true);\n      log.debug(\"setting up client settings\");\n      Map<String, Object> settings = new HashMap<>();\n      settings.put(SharedSettings.DEBUG_KEY, debug);\n      settings.put(SharedSettings.DUMP_DIR_KEY, dumpClasses ? dumpDir : \"\");\n      settings.put(SharedSettings.TRACK_RETRANSFORMS_KEY, trackRetransforms);\n      settings.put(SharedSettings.TRUSTED_KEY, trusted);\n      settings.put(SharedSettings.PROBE_DESC_PATH_KEY, probeDescPath);\n      settings.put(SharedSettings.OUTPUT_FILE_KEY, outputFile);\n\n      protocol.write(new SetSettingsCommand(settings));\n\n      if (log.isDebugEnabled()) {\n        log.debug(\"sending instrument command: {}\", Arrays.deepToString(args));\n      }\n      protocol.write(new InstrumentCommand(code, args));\n\n      log.debug(\"entering into command loop\");\n      commandLoop(\n          new CommandListener() {\n            boolean statusReported = false;\n\n            @Override\n            public void onCommand(Command cmd) throws IOException {\n              if (statusReported || cmd.getType() != Command.STATUS) {\n                listener.onCommand(cmd);\n              } else {\n                StatusCommand statusCommand = (StatusCommand) cmd;\n                if (statusCommand.getFlag() == StatusCommand.STATUS_FLAG) {\n                  if (statusCommand.isSuccess()) {\n                    log.info(\"Successfully started BTrace probe: {}\", fileName);\n                  } else {\n                    log.warn(\"Failed to start BTrace probe: {}\", fileName);\n                    System.exit(1);\n                  }\n                  statusReported = true;\n                  // Forward the first STATUS as well so higher-level listeners (e.g. unattended -x)\n                  // can react immediately (e.g. initiate disconnect)\n                  listener.onCommand(cmd);\n                } else {\n                  listener.onCommand(cmd);\n                }\n              }\n            }\n          });\n    } catch (UnknownHostException uhe) {\n      throw new IOException(uhe);\n    } catch (InterruptedException e) {\n      Thread.currentThread().interrupt();\n    }\n  }\n\n  /**\n   * Submits the compiled BTrace .class to the VM attached and passes given command line arguments.\n   * Receives commands from the traced JVM and sends those to the command listener provided.\n   */\n  public void submit(byte[] code, String[] args, CommandListener listener) throws IOException {\n    submit(null, code, args, listener);\n  }\n\n  /** Sends ExitCommand to the traced JVM. */\n  public void sendExit() throws IOException {\n    sendExit(0);\n  }\n\n  /** Sends ExitCommand to the traced JVM. */\n  public void sendExit(int code) throws IOException {\n    send(new ExitCommand(code));\n  }\n\n  public void sendDisconnect() throws IOException {\n    if (log.isDebugEnabled()) {\n      log.debug(\"sending command {}\", DisconnectCommand.class.getSimpleName());\n    }\n    send(new DisconnectCommand());\n  }\n\n  /** Sends an EventCommand to the traced JVM. */\n  public void sendEvent() throws IOException {\n    sendEvent(\"\");\n  }\n\n  /** Sends an EventCommand to the traced JVM. */\n  public void sendEvent(String name) throws IOException {\n    send(new EventCommand(name));\n  }\n\n  /** Closes all connection state to the traced JVM. */\n  public synchronized void close() throws IOException {\n    // Mark as disconnected to prevent shutdown hook from attempting further sends\n    disconnected = true;\n    if (protocol != null) {\n      protocol.close();\n    }\n    if (sock != null) {\n      sock.close();\n    }\n    reset();\n  }\n\n  boolean isDisconnected() {\n    return disconnected;\n  }\n\n  void disconnect() throws IOException {\n    disconnected = true;\n    if (log.isDebugEnabled()) {\n      log.debug(\"sending DISCONNECT request to agent\");\n    }\n    sendDisconnect();\n  }\n\n  void listProbes() throws IOException {\n    send(new ListProbesCommand());\n  }\n\n  void listFailedExtensions() throws IOException {\n    send(new ListFailedExtensionsCommand());\n  }\n\n  /** reset the internal status of the client */\n  private void reset() {\n    sock = null;\n    protocol = null;\n  }\n\n  /**\n   * Finds the masked btrace.jar in the classpath.\n   *\n   * @return the path to the masked JAR, or null if not found\n   */\n  private String findMaskedAgentJar() {\n    try {\n      // 1. Check system property (set by Loader.main())\n      String maskedJarPath = System.getProperty(\"btrace.jar.path\");\n      if (maskedJarPath != null && !maskedJarPath.isEmpty()) {\n        File maskedJar = new File(maskedJarPath);\n        if (maskedJar.exists() && maskedJar.isFile() && isMaskedJar(maskedJar)) {\n          if (log.isDebugEnabled()) {\n            log.debug(\"Using masked JAR from property: {}\", maskedJar.getAbsolutePath());\n          }\n          return maskedJar.getAbsolutePath();\n        }\n      }\n\n      // 2. Search classpath for btrace.jar\n      String classpath = System.getProperty(\"java.class.path\", \"\");\n      for (String entry : classpath.split(File.pathSeparator)) {\n        if (entry.endsWith(\"btrace.jar\")) {\n          File jarFile = new File(entry);\n          if (jarFile.exists() && isMaskedJar(jarFile)) {\n            if (log.isDebugEnabled()) {\n              log.debug(\"Found masked btrace.jar in classpath: {}\", jarFile.getAbsolutePath());\n            }\n            return jarFile.getAbsolutePath();\n          }\n        }\n      }\n\n      // 3. No masked JAR found\n      return null;\n    } catch (Exception e) {\n      if (log.isDebugEnabled()) {\n        log.debug(\"Failed to find masked agent JAR: {}\", e.getMessage());\n      }\n      return null;\n    }\n  }\n\n  /**\n   * Check if a JAR file has the masked JAR structure (contains Loader and masked .classdata files)\n   */\n  private boolean isMaskedJar(File jarFile) {\n    try (JarFile jar = new JarFile(jarFile)) {\n      // Check for Loader class (unmasked entry point)\n      if (jar.getJarEntry(\"org/openjdk/btrace/boot/Loader.class\") == null) {\n        return false;\n      }\n      // Check for masked agent classes\n      if (jar.getJarEntry(\"META-INF/btrace/agent/\") != null) {\n        return true;\n      }\n      // Also check for at least one .classdata file\n      Enumeration<JarEntry> entries = jar.entries();\n      while (entries.hasMoreElements()) {\n        JarEntry entry = entries.nextElement();\n        if (entry.getName().endsWith(\".classdata\")) {\n          return true;\n        }\n      }\n      return false;\n    } catch (IOException e) {\n      if (log.isDebugEnabled()) {\n        log.debug(\"Failed to check if JAR is masked: {}\", e.getMessage());\n      }\n      return false;\n    }\n  }\n\n  // -- Internals only below this point\n  private String getToolsJarPath(String javaClassPath, String javaHome) {\n    // try to get absolute path of tools.jar\n    // first check this application's classpath\n    String[] components = javaClassPath.split(File.pathSeparator);\n    for (String c : components) {\n      if (c.endsWith(\"tools.jar\")) {\n        return new File(c).getAbsolutePath();\n      } else if (c.endsWith(\"classes.jar\")) { // MacOS specific\n        return new File(c).getAbsolutePath();\n      }\n    }\n    // we didn't find -- make a guess! If this app is running on a JDK rather\n    // than a JRE there will be a tools.jar in $JDK_HOME/lib directory.\n    if (System.getProperty(\"os.name\").startsWith(\"Mac\")) {\n      int homeIndex = javaHome.indexOf(\"/Home\");\n      if (homeIndex > -1) {\n        String java_mac_home = javaHome.substring(0, javaHome.indexOf(\"/Home\"));\n        return java_mac_home + \"/Home/lib/tools.jar\";\n      }\n    }\n    // tools.jar is not included in JRE\n    return javaHome + (javaHome.contains(\"/jre\") ? \"/..\" : \"\") + \"/lib/tools.jar\";\n  }\n\n  private void send(Command cmd) throws IOException {\n    if (protocol == null) {\n      throw new IllegalStateException();\n    }\n    protocol.write(cmd);\n  }\n\n  private void commandLoop(CommandListener listener) throws IOException {\n    assert protocol != null : \"null protocol?\";\n    AtomicBoolean exited = new AtomicBoolean(false);\n    while (true) {\n      try {\n        Command cmd = protocol.read();\n        if (log.isDebugEnabled()) {\n          log.debug(\"received command {}\", cmd);\n        }\n        listener.onCommand(cmd);\n        if (cmd.getType() == Command.EXIT) {\n          log.debug(\"received EXIT cmd\");\n          return;\n        }\n      } catch (IOException e) {\n        if (exited.compareAndSet(false, true)) listener.onCommand(new ExitCommand(-1));\n        throw e;\n      } catch (ClassNotFoundException e) {\n        if (exited.compareAndSet(false, true)) listener.onCommand(new ExitCommand(-1));\n        throw new IOException(e);\n      } catch (NullPointerException e) {\n        if (exited.compareAndSet(false, true)) listener.onCommand(new ExitCommand(-1));\n        throw new IOException(\"Protocol closed during command processing\", e);\n      }\n    }\n  }\n\n  private void warn(CommandListener listener, String msg) {\n    try {\n      msg = \"WARNING: \" + msg + \"\\n\";\n      listener.onCommand(new MessageCommand(msg));\n    } catch (IOException exp) {\n      if (log.isDebugEnabled()) {\n        log.debug(\"Failed to send warning messge\", exp);\n      }\n    }\n  }\n\n  private void submitDTrace(String fileName, byte[] code, String[] args, CommandListener listener) {\n    if (fileName == null || code == null) {\n      return;\n    }\n\n    Object dtraceSrc = getDTraceSource(fileName, code);\n    try {\n      if (dtraceSrc instanceof String) {\n        if (dtraceEnabled) {\n          submitString.invoke(null, dtraceSrc, args, listener);\n        } else {\n          warn(listener, \"@DTrace is supported only on Solaris 11+\");\n        }\n      } else if (dtraceSrc instanceof File) {\n        if (dtraceEnabled) {\n          submitFile.invoke(null, dtraceSrc, args, listener);\n        } else {\n          warn(listener, \"@DTraceRef is supported only on Solaris 11+\");\n        }\n      }\n    } catch (IllegalAccessException | IllegalArgumentException iace) {\n      iace.printStackTrace();\n    } catch (InvocationTargetException ite) {\n      throw new RuntimeException(ite.getTargetException());\n    }\n  }\n\n  private Object getDTraceSource(String fileName, byte[] code) {\n    if (isPersistedProbe(code)) {\n      return null;\n    }\n\n    ClassReader reader = new ClassReader(code);\n    Object[] result = new Object[1];\n    reader.accept(\n        new ClassVisitor(Opcodes.ASM9) {\n\n          @Override\n          public AnnotationVisitor visitAnnotation(String desc, boolean vis) {\n            if (desc.equals(DTRACE_DESC)) {\n              return new AnnotationVisitor(Opcodes.ASM9) {\n\n                @Override\n                public void visit(String name, Object value) {\n                  if (name.equals(\"value\")) {\n                    result[0] = value;\n                  }\n                }\n              };\n            } else if (desc.equals(DTRACE_REF_DESC)) {\n              return new AnnotationVisitor(Opcodes.ASM9) {\n\n                @Override\n                public void visit(String name, Object value) {\n                  if (name.equals(\"value\")) {\n                    String tmp = value.toString();\n                    File file = new File(tmp);\n                    if (file.isAbsolute()) {\n                      result[0] = file;\n                    } else {\n                      int index = fileName.lastIndexOf(File.separatorChar);\n                      String dir;\n                      if (index == -1) {\n                        dir = \".\";\n                      } else {\n                        dir = fileName.substring(0, index);\n                      }\n                      result[0] = new File(dir, tmp);\n                    }\n                  }\n                }\n              };\n            } else {\n              return super.visitAnnotation(desc, vis);\n            }\n          }\n        },\n        ClassReader.SKIP_CODE);\n    return result[0];\n  }\n\n  private static boolean isPersistedProbe(byte[] code) {\n    return code[0] == (byte) (0xBA & 0xff)\n        && code[1] == (byte) (0xCE & 0xff)\n        && code[2] == (byte) (0XCA & 0xff)\n        && code[3] == (byte) (0XCA & 0xff);\n  }\n}\n"
  },
  {
    "path": "btrace-client/src/main/java/org/openjdk/btrace/client/JpsUtils.java",
    "content": "package org.openjdk.btrace.client;\n\nimport com.sun.tools.attach.VirtualMachine;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport sun.jvmstat.monitor.MonitoredHost;\nimport sun.jvmstat.monitor.MonitoredVm;\nimport sun.jvmstat.monitor.MonitoredVmUtil;\nimport sun.jvmstat.monitor.VmIdentifier;\n\nfinal class JpsUtils {\n  private static final Logger log = LoggerFactory.getLogger(JpsUtils.class);\n\n  static Integer findVmByName(String name) {\n    try {\n      return Integer.parseInt(name);\n    } catch (NumberFormatException ignored) {\n      Integer pid = null;\n      try {\n        MonitoredHost vmHost = MonitoredHost.getMonitoredHost((String) null);\n        for (Integer vmPid : MonitoredHost.getMonitoredHost(\"localhost\").activeVms()) {\n          VmIdentifier id = new VmIdentifier(vmPid.toString());\n          MonitoredVm vm = vmHost.getMonitoredVm(id);\n          String mainClass = MonitoredVmUtil.mainClass(vm, false);\n          if (name.equalsIgnoreCase(mainClass)) {\n            pid = vmPid;\n            break;\n          }\n        }\n      } catch (Exception e) {\n        log.warn(\"Unexpected exception\", e);\n      }\n      return pid;\n    }\n  }\n\n  static Collection<String> listVms() {\n    Collection<String> vms = new ArrayList<>();\n    try {\n      MonitoredHost vmHost = MonitoredHost.getMonitoredHost((String) null);\n      for (Integer vmPid : MonitoredHost.getMonitoredHost(\"localhost\").activeVms()) {\n        VmIdentifier id = new VmIdentifier(vmPid.toString());\n        MonitoredVm mvm = vmHost.getMonitoredVm(id);\n        if (MonitoredVmUtil.isAttachable(mvm)) {\n          String mainClass = MonitoredVmUtil.mainClass(mvm, false);\n\n          vms.add(\n              \"(\"\n                  + (hasBTraceServer(vmPid) ? \"+\" : \"-\")\n                  + \") \"\n                  + vmPid\n                  + \" \"\n                  + mainClass\n                  + \" [\"\n                  + MonitoredVmUtil.commandLine(mvm)\n                  + \"]\");\n        }\n      }\n    } catch (Exception e) {\n      log.warn(\"Unexpected exception\", e);\n    }\n    return vms;\n  }\n\n  static boolean hasBTraceServer(int pid) {\n    boolean result = false;\n    VirtualMachine vm = null;\n    try {\n      vm = VirtualMachine.attach(String.valueOf(pid));\n      result = vm.getSystemProperties().containsKey(\"btrace.port\");\n    } catch (Throwable ignored) {\n    } finally {\n      if (vm != null) {\n        try {\n          vm.detach();\n        } catch (IOException ignored) {\n        }\n      }\n    }\n    return result;\n  }\n}\n"
  },
  {
    "path": "btrace-client/src/main/java/org/openjdk/btrace/client/Main.java",
    "content": "/*\n * Copyright (c) 2008-2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.client;\n\nimport java.io.Console;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.PrintWriter;\nimport java.net.URI;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.Properties;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport org.openjdk.btrace.compiler.oneliner.OnelinerAST.OnelinerNode;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerCodeGenerator;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerException;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerParser;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerValidator;\nimport org.openjdk.btrace.core.DebugSupport;\nimport org.openjdk.btrace.core.Messages;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.openjdk.btrace.core.comm.ExitCommand;\nimport org.openjdk.btrace.core.comm.PrintableCommand;\nimport org.openjdk.btrace.core.comm.StatusCommand;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport sun.misc.Signal;\n\n/**\n * This is the main class for a simple command line BTrace client. It is possible to create a GUI\n * client using the Client class.\n *\n * @author A. Sundararajan\n */\n@SuppressWarnings(\"RedundantThrows\")\npublic final class Main {\n  private static final Logger log;\n\n  public static final boolean TRACK_RETRANSFORM;\n  public static final int BTRACE_DEFAULT_PORT = 2020;\n  public static final String BTRACE_DEFAULT_HOST = \"localhost\";\n  private static final Console con;\n  private static final PrintWriter out;\n  public static volatile boolean exiting;\n  private static boolean DEBUG;\n  private static boolean TRUSTED;\n  private static boolean DUMP_CLASSES;\n  private static String OUTPUT_FILE;\n  private static String DUMP_DIR;\n  private static String PROBE_DESC_PATH;\n  private static String AGENT_JAR_OVERRIDE;\n  private static String BOOT_JAR_OVERRIDE;\n  private static String EXTRACT_AGENT_DIR;\n  private static boolean ONELINER_MODE;\n  private static String ONELINER_SCRIPT;\n\n  static {\n    DebugSupport.initLoggers(Boolean.getBoolean(\"com.sun.btrace.debug\"), null);\n    // initialize the logger instance\n    log = LoggerFactory.getLogger(Main.class);\n\n    if (isDebug()) {\n      log.debug(\"btrace debug mode is set\");\n    }\n    TRACK_RETRANSFORM = Boolean.getBoolean(\"com.sun.btrace.trackRetransforms\");\n    if (TRACK_RETRANSFORM) log.debug(\"trackRetransforms flag is set\");\n    TRUSTED = Boolean.getBoolean(\"com.sun.btrace.unsafe\");\n    TRUSTED |= Boolean.getBoolean(\"com.sun.btrace.trusted\");\n    if (TRUSTED) log.debug(\"btrace trusted mode is set\");\n    DUMP_CLASSES = Boolean.getBoolean(\"com.sun.btrace.dumpClasses\");\n    if (DUMP_CLASSES) log.debug(\"dumpClasses flag is set\");\n    DUMP_DIR = System.getProperty(\"com.sun.btrace.dumpDir\", \".\");\n    if (DUMP_CLASSES) {\n      if (log.isDebugEnabled()) log.debug(\"dumpDir is {}\", DUMP_DIR);\n    }\n    PROBE_DESC_PATH = System.getProperty(\"com.sun.btrace.probeDescPath\", \".\");\n    String javaVersion = getJavaVersion();\n    // In Java 22 the console will write standard output to stderr :shrug:\n    con = javaVersion == null || !javaVersion.startsWith(\"22\") ? System.console() : null;\n    out = getOutWriter(con);\n  }\n\n  private static String getJavaVersion() {\n    Properties props = new Properties();\n    try {\n      props.load(Files.newInputStream(Paths.get(System.getenv(\"JAVA_HOME\"), \"release\")));\n      return props.getProperty(\"JAVA_VERSION\").replace(\"\\\"\", \"\");\n    } catch (IOException ignored) {\n      return null;\n    }\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  private static PrintWriter getOutWriter(Console con) {\n    return (con != null) ? con.writer() : new PrintWriter(System.out);\n  }\n\n  public static void main(String[] args) throws Exception {\n    int port = BTRACE_DEFAULT_PORT;\n    String host = BTRACE_DEFAULT_HOST;\n    String classPath = \".\";\n    String includePath = null;\n\n    int count = 0;\n    boolean hostDefined = false;\n    boolean portDefined = false;\n    boolean classpathDefined = false;\n    boolean includePathDefined = false;\n    String statsdDef = \"\";\n    String resumeProbe = null;\n    String probeCommand = null;\n    String probeCommandArg = null;\n    boolean listProbes = false;\n    boolean listFailedExtensions = false;\n    boolean unattended = false;\n\n    for (int i = 0; i < args.length; i++) {\n      String arg = args[i];\n      switch (arg) {\n        case \"-v\":\n          DEBUG = true;\n          DebugSupport.initLoggers(true, log);\n          break;\n        case \"--version\":\n          System.out.println(Messages.get(\"btrace.version\"));\n          return;\n        case \"-l\":\n          for (String vm : JpsUtils.listVms()) {\n            System.out.println(vm);\n          }\n          return;\n        case \"-r\":\n          if (i < args.length - 1) {\n            if (args[i + 1].equalsIgnoreCase(\"help\")) {\n              System.out.println(Messages.get(\"remote.commands.help\"));\n              return;\n            }\n          }\n          break;\n        case \"--extract-agent\":\n          if (i < args.length - 1 && !args[i + 1].startsWith(\"-\")) {\n            EXTRACT_AGENT_DIR = args[i + 1];\n          } else {\n            EXTRACT_AGENT_DIR = \".\";\n          }\n          handleExtractAgent();\n          return;\n      }\n    }\n\n    if (args.length < 2) {\n      usage();\n    }\n\n    for (; ; ) {\n      if (args[count].isEmpty()) {\n        continue;\n      }\n      if (args[count].charAt(0) == '-') {\n        if (args.length <= count + 1) {\n          usage();\n        }\n        if (args[count].equals(\"-p\") && !portDefined) {\n          try {\n            port = Integer.parseInt(args[++count]);\n            if (log.isDebugEnabled()) log.debug(\"accepting port {}\", port);\n          } catch (NumberFormatException nfe) {\n            usage();\n          }\n          portDefined = true;\n        } else if (args[count].equals(\"-u\")) {\n          TRUSTED = true;\n          log.debug(\"btrace trusted mode is set\");\n        } else if (args[count].equals(\"-o\")) {\n          OUTPUT_FILE = args[++count];\n          if (log.isDebugEnabled()) log.debug(\"outputFile is {}\", OUTPUT_FILE);\n        } else if (args[count].equals(\"-d\")) {\n          DUMP_CLASSES = true;\n          DUMP_DIR = args[++count];\n          if (log.isDebugEnabled()) log.debug(\"dumpDir is {}\", DUMP_DIR);\n        } else if (args[count].equals(\"-pd\")) {\n          PROBE_DESC_PATH = args[++count];\n          if (log.isDebugEnabled()) log.debug(\"probeDescDir is {}\", PROBE_DESC_PATH);\n        } else if ((args[count].equals(\"-cp\") || args[count].equals(\"-classpath\"))\n            && !classpathDefined) {\n          classPath = args[++count];\n          if (log.isDebugEnabled()) log.debug(\"accepting classpath {}\", classPath);\n          classpathDefined = true;\n        } else if (args[count].equals(\"-I\") && !includePathDefined) {\n          includePath = args[++count];\n          if (log.isDebugEnabled()) log.debug(\"accepting include path {}\", includePath);\n          includePathDefined = true;\n        } else if (args[count].equals(\"-statsd\")) {\n          statsdDef = args[++count];\n        } else if (args[count].equals(\"-v\")) {\n          // already processed\n        } else if (args[count].equals(\"-host\") && !hostDefined) {\n          host = args[++count];\n          hostDefined = true;\n        } else if (args[count].equals(\"-r\")) {\n          if (log.isDebugEnabled())\n            log.debug(\"reconnecting to an already active probe {}\", resumeProbe);\n          resumeProbe = args[++count];\n          if (count < args.length - 2 && !args[count + 1].startsWith(\"-\")) {\n            probeCommand = args[++count].toLowerCase();\n            if (probeCommand.equalsIgnoreCase(\"event\") && count < args.length - 2) {\n              probeCommandArg = args[++count];\n            }\n          }\n          if (probeCommand != null && log.isDebugEnabled()) {\n            log.debug(\n                \"executing probe command '{}'{}\",\n                probeCommand,\n                (probeCommandArg != null ? \"(\" + probeCommandArg + \")\" : \"\"));\n          }\n        } else if (args[count].equals(\"-lp\")) {\n          log.debug(\"listing active probes\");\n          listProbes = true;\n        } else if (args[count].equals(\"-le\")) {\n          log.debug(\"listing failed extensions\");\n          listFailedExtensions = true;\n        } else if (args[count].equals(\"-x\")) {\n          log.debug(\"submitting probe in unattended mode\");\n          unattended = true;\n        } else if (args[count].equals(\"--agent-jar\")) {\n          AGENT_JAR_OVERRIDE = args[++count];\n          if (log.isDebugEnabled()) log.debug(\"agent JAR override: {}\", AGENT_JAR_OVERRIDE);\n        } else if (args[count].equals(\"--boot-jar\")) {\n          BOOT_JAR_OVERRIDE = args[++count];\n          if (log.isDebugEnabled()) log.debug(\"boot JAR override: {}\", BOOT_JAR_OVERRIDE);\n        } else if (args[count].equals(\"-n\") || args[count].equals(\"--oneliner\")) {\n          ONELINER_MODE = true;\n          ONELINER_SCRIPT = args[++count];\n          if (log.isDebugEnabled()) log.debug(\"oneliner: {}\", ONELINER_SCRIPT);\n        } else {\n          usage();\n        }\n        count++;\n        if (count >= args.length) {\n          break;\n        }\n      } else {\n        break;\n      }\n    }\n\n    if (!portDefined) {\n      if (log.isDebugEnabled()) log.debug(\"assuming default port {}\", port);\n    }\n\n    if (!classpathDefined) {\n      if (log.isDebugEnabled()) log.debug(\"assuming default classpath '{}'\", classPath);\n    }\n\n    if (args.length < (count + 1)) {\n      usage();\n    }\n\n    String pidArg = args[count];\n    Integer pid = JpsUtils.findVmByName(pidArg);\n    if (pid == null) {\n      errorExit(\"Unable to find JVM with either PID or name: \" + pidArg, 1);\n    } else {\n      log.info(\"Attaching BTrace to PID: {}\", pid);\n    }\n\n    try {\n      Client client =\n          new Client(\n              port,\n              OUTPUT_FILE,\n              PROBE_DESC_PATH,\n              DEBUG,\n              TRACK_RETRANSFORM,\n              TRUSTED,\n              DUMP_CLASSES,\n              DUMP_DIR,\n              statsdDef,\n              AGENT_JAR_OVERRIDE,\n              BOOT_JAR_OVERRIDE);\n      if (resumeProbe != null) {\n        registerExitHook(client);\n        if (con != null) {\n          registerSignalHandler(client);\n        }\n        client.reconnect(\n            host,\n            resumeProbe,\n            createCommandListener(client),\n            new String[] {probeCommand, probeCommandArg});\n      } else if (listProbes) {\n        registerExitHook(client);\n        client.attach(pid.toString(), null, classPath);\n        client.connectAndListProbes(host, createCommandListener(client));\n        System.exit(0);\n      } else if (listFailedExtensions) {\n        registerExitHook(client);\n        client.attach(pid.toString(), null, classPath);\n        client.connectAndListFailedExtensions(host, createCommandListener(client));\n        System.exit(0);\n      } else {\n        String fileName;\n        byte[] code;\n        String[] btraceArgs;\n\n        if (ONELINER_MODE) {\n          // Oneliner mode: parse and generate Java source from oneliner\n          try {\n            OnelinerNode ast = OnelinerParser.parse(ONELINER_SCRIPT);\n            OnelinerValidator.validate(ast, ONELINER_SCRIPT);\n            String className = \"BTraceOneliner_\" + System.currentTimeMillis();\n            String javaSource = OnelinerCodeGenerator.generate(ast, className);\n            fileName = className + \".java\";\n\n            // Extract script args\n            btraceArgs = new String[args.length - count - 1];\n            if (btraceArgs.length > 0) {\n              System.arraycopy(args, count + 1, btraceArgs, 0, btraceArgs.length);\n            }\n\n            if (log.isDebugEnabled()) {\n              log.debug(\"Generated BTrace source:\\n{}\", javaSource);\n            }\n            if (Boolean.getBoolean(\"btrace.oneliner.dump\")) {\n              System.err.println(\"=== Generated oneliner source (\" + fileName + \") ===\");\n              System.err.println(javaSource);\n            }\n            code = client.compileSource(fileName, javaSource, classPath, new PrintWriter(System.err), includePath);\n            if (code == null) {\n              errorExit(\"Oneliner compilation failed\", 1);\n            }\n          } catch (OnelinerException e) {\n            errorExit(e.getMessage(), 1);\n            return;\n          }\n        } else {\n          // File mode: compile from file\n          fileName = args[count + 1];\n          btraceArgs = new String[args.length - count - 2];\n          if (btraceArgs.length > 0) {\n            System.arraycopy(args, count + 2, btraceArgs, 0, btraceArgs.length);\n          }\n          if (!new File(fileName).exists()) {\n            errorExit(\"File not found: \" + fileName, 1);\n          }\n          code = client.compile(fileName, classPath, includePath);\n          if (code == null) {\n            errorExit(\"BTrace compilation failed\", 1);\n          }\n        }\n        if (log.isDebugEnabled()) {\n          log.debug(\"Boot classpath: {}\", classPath);\n        }\n        if (!hostDefined) client.attach(pid.toString(), null, classPath);\n        registerExitHook(client);\n        if (con != null) {\n          registerSignalHandler(client);\n        }\n        log.debug(\"submitting the BTrace program\");\n        CommandListener listener = createCommandListener(client);\n\n        final boolean isUnattended = unattended;\n        client.submit(\n            host,\n            fileName,\n            code,\n            btraceArgs,\n            cmd -> {\n              if (isUnattended\n                  && cmd.getType() == Command.STATUS\n                  && ((StatusCommand) cmd).getFlag() == StatusCommand.STATUS_FLAG) {\n                // In unattended mode, initiate a graceful disconnect and\n                // continue processing so the server can send DISCONNECT\n                // with the probe id, which the client prints.\n                try {\n                  if (log.isDebugEnabled()) {\n                    log.debug(\"initiating unattended disconnect after STATUS OK\");\n                  }\n                  client.disconnect(); // marks disconnected and sends DISCONNECT\n                } catch (IOException ioe) {\n                  if (log.isDebugEnabled()) {\n                    log.debug(\"error initiating unattended disconnect: {}\", ioe.toString());\n                  }\n                }\n                // Continue processing commands so DISCONNECT is handled.\n              } else {\n                listener.onCommand(cmd);\n              }\n            });\n      }\n    } catch (IOException exp) {\n      errorExit(exp.getMessage(), 1);\n    }\n  }\n\n  private static CommandListener createCommandListener(Client client) {\n    return cmd -> {\n      int type = cmd.getType();\n      if (cmd instanceof PrintableCommand) {\n        ((PrintableCommand) cmd).print(out);\n        out.flush();\n      } else if (type == Command.EXIT) {\n        exiting = true;\n        out.flush();\n        ExitCommand ecmd = (ExitCommand) cmd;\n        System.exit(ecmd.getExitCode());\n      }\n      if (type == Command.DISCONNECT) {\n        System.exit(0);\n      }\n    };\n  }\n\n  private static void registerExitHook(Client client) {\n    log.debug(\"registering shutdown hook\");\n    Runtime.getRuntime()\n        .addShutdownHook(\n            new Thread(\n                () -> {\n                  if (!exiting) {\n                    try {\n                      if (!client.isDisconnected()) {\n                        log.debug(\"sending exit command\");\n                        client.sendExit(0);\n                      } else {\n                        // Disconnect already initiated; avoid duplicate sends on shutdown\n                        log.debug(\"client already marked disconnected; skipping shutdown send\");\n                      }\n                    } catch (IOException | IllegalStateException ioexp) {\n                      // Streams may already be closed (e.g., unattended mode)\n                      if (log.isDebugEnabled()) log.debug(ioexp.toString(), ioexp);\n                    }\n                  }\n                }));\n  }\n\n  private static void registerSignalHandler(Client client) {\n    log.debug(\"registering signal handler for SIGINT\");\n    Signal.handle(\n        new Signal(\"INT\"),\n        sig -> {\n          try {\n            con.printf(\"Please enter your option:\\n\");\n            con.printf(\n                \"\\t1. exit\\n\\t2. send an event\\n\\t3. send a named event\\n\\t4. flush console output\\n\\t5. list probes\\n\\t6. detach client\\n\\t7. list failed extensions\\n\");\n            con.flush();\n            String option = con.readLine();\n            if (option == null) {\n              return;\n            }\n            option = option.trim();\n            switch (option) {\n              case \"1\":\n                System.exit(0);\n              case \"2\":\n                log.debug(\"sending event command\");\n                client.sendEvent();\n                break;\n              case \"3\":\n                con.printf(\"Please enter the event name: \");\n                String name = con.readLine();\n                if (name != null) {\n                  log.debug(\"sending event command\");\n                  client.sendEvent(name);\n                }\n                break;\n              case \"4\":\n                out.flush();\n                break;\n              case \"5\":\n                client.listProbes();\n                break;\n              case \"6\":\n                client.disconnect();\n                break;\n              case \"7\":\n                client.listFailedExtensions();\n                break;\n              default:\n                con.printf(\"invalid option!\\n\");\n                break;\n            }\n          } catch (IOException ioexp) {\n            log.debug(ioexp.toString(), ioexp);\n          }\n        });\n  }\n\n  private static void usage() {\n    System.err.println(Messages.get(\"btrace.usage\"));\n    System.exit(1);\n  }\n\n  private static boolean isDebug() {\n    return DEBUG;\n  }\n\n  private static void errorExit(String msg, int code) {\n    exiting = true;\n    System.err.println(msg);\n    System.exit(code);\n  }\n\n  /**\n   * Extracts embedded agent JARs from the uber JAR to the specified directory.\n   */\n  private static void handleExtractAgent() {\n    if (EXTRACT_AGENT_DIR == null) {\n      return;\n    }\n\n    File outputDir = new File(EXTRACT_AGENT_DIR);\n    if (outputDir.exists() && !outputDir.isDirectory()) {\n      errorExit(\"Output path is not a directory: \" + outputDir.getAbsolutePath(), 1);\n    }\n    if (!outputDir.exists() && !outputDir.mkdirs()) {\n      errorExit(\"Failed to create output directory: \" + outputDir.getAbsolutePath(), 1);\n    }\n\n    URL btraceLoc = Main.class.getProtectionDomain().getCodeSource().getLocation();\n    if (btraceLoc == null) {\n      errorExit(\"Unable to locate BTrace JAR for extraction.\", 1);\n    }\n\n    File btraceFile;\n    try {\n      btraceFile = new File(btraceLoc.toURI());\n    } catch (Exception e) {\n      errorExit(\"Invalid BTrace location: \" + btraceLoc, 1);\n      return;\n    }\n\n    if (!btraceFile.isFile()) {\n      errorExit(\"BTrace location is not a JAR file: \" + btraceFile.getAbsolutePath(), 1);\n    }\n\n    try (JarFile btrace = new JarFile(btraceFile)) {\n      File agentFile = new File(outputDir, \"btrace-agent.jar\");\n      File bootFile = new File(outputDir, \"btrace-boot.jar\");\n\n      extractJar(btrace, \"META-INF/embedded/btrace-agent.jar\", agentFile);\n      extractJar(btrace, \"META-INF/embedded/btrace-boot.jar\", bootFile);\n\n      System.out.println(\"Extracted agent JARs to: \" + outputDir.getAbsolutePath());\n      System.out.println(\"  - \" + agentFile.getName());\n      System.out.println(\"  - \" + bootFile.getName());\n      System.exit(0);\n    } catch (Exception e) {\n      errorExit(\"Failed to extract agent JARs: \" + e.getMessage(), 1);\n    }\n  }\n\n  /**\n   * Extracts a single JAR entry from the source JAR to the target file.\n   */\n  private static void extractJar(JarFile source, String entryPath, File target)\n      throws IOException {\n    JarEntry entry = source.getJarEntry(entryPath);\n    if (entry == null) {\n      throw new IOException(\"Embedded JAR not found: \" + entryPath);\n    }\n    // Validate that the entry name does not contain path traversal sequences\n    String normalizedEntry = entry.getName();\n    if (normalizedEntry.contains(\"..\")) {\n      throw new IOException(\"Zip Slip: entry contains path traversal: \" + normalizedEntry);\n    }\n\n    try (InputStream in = source.getInputStream(entry);\n        OutputStream out = new FileOutputStream(target)) {\n      byte[] buffer = new byte[8192];\n      int bytesRead;\n      while ((bytesRead = in.read(buffer)) != -1) {\n        out.write(buffer, 0, bytesRead);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-client/src/main/java/org/openjdk/btrace/client/ProbePrinter.java",
    "content": "package org.openjdk.btrace.client;\n\nimport java.io.BufferedInputStream;\nimport java.io.FileInputStream;\nimport java.io.InputStream;\nimport java.io.PrintWriter;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Set;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.util.TraceClassVisitor;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.instr.BTraceProbe;\nimport org.openjdk.btrace.instr.BTraceProbeFactory;\nimport org.openjdk.btrace.instr.OnMethod;\nimport org.openjdk.btrace.instr.OnProbe;\n\npublic final class ProbePrinter {\n  public static void main(String[] args) throws Exception {\n    if (args.length != 1) {\n      System.out.println(\"Usage: btracep <probe_file>\");\n      System.exit(0);\n    }\n    Path probePath = Paths.get(args[0]);\n\n    try (InputStream probeDataStream =\n        new BufferedInputStream(new FileInputStream(probePath.toFile()))) {\n      BTraceProbe probe =\n          new BTraceProbeFactory(SharedSettings.GLOBAL).createProbe(probeDataStream);\n\n      probe.checkVerified();\n      System.out.println(\"Name: \" + probe.getClassName(false));\n      System.out.println(\"Verified: \" + probe.isVerified());\n      System.out.println(\"Transforming: \" + probe.isTransforming());\n\n      Set<Permission> requiredPermissions = probe.getRequiredPermissions();\n      if (!requiredPermissions.isEmpty()) {\n        System.out.println(\"Required permissions: \" + requiredPermissions);\n      }\n\n      System.out.println(\"=== Probe handlers\");\n      for (OnMethod om : probe.onmethods()) {\n        System.out.println(om);\n      }\n      for (OnProbe op : probe.onprobes()) {\n        System.out.println(op);\n      }\n\n      System.out.println(\"=== Dataholder class\");\n      ClassReader dataholderReader = new ClassReader(probe.getDataHolderBytecode());\n      dataholderReader.accept(new TraceClassVisitor(new PrintWriter(System.out)), 0);\n\n      System.out.println(\"=== Full probe class\");\n      ClassReader probeReader = new ClassReader(probe.getFullBytecode());\n      probeReader.accept(new TraceClassVisitor(new PrintWriter(System.out)), 0);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-client/src/test/java/org/openjdk/btrace/client/ClientTest.java",
    "content": "package org.openjdk.btrace.client;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.lang.reflect.Field;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nclass ClientTest {\n\n  @TempDir Path tempDir;\n\n  private File createUberJar() throws IOException {\n    File uberJar = tempDir.resolve(\"btrace.jar\").toFile();\n\n    try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(uberJar))) {\n      // Add a dummy embedded agent JAR\n      JarEntry agentEntry = new JarEntry(\"META-INF/embedded/btrace-agent.jar\");\n      jos.putNextEntry(agentEntry);\n      jos.write(\"dummy agent content\".getBytes());\n      jos.closeEntry();\n\n      // Add a dummy embedded boot JAR\n      JarEntry bootEntry = new JarEntry(\"META-INF/embedded/btrace-boot.jar\");\n      jos.putNextEntry(bootEntry);\n      jos.write(\"dummy boot content\".getBytes());\n      jos.closeEntry();\n\n      // Add a marker class to make it a valid JAR\n      JarEntry classEntry = new JarEntry(\"org/openjdk/btrace/client/Client.class\");\n      jos.putNextEntry(classEntry);\n      jos.write(new byte[0]);\n      jos.closeEntry();\n    }\n\n    return uberJar;\n  }\n\n  @Test\n  void testConstructorWithOverrides() {\n    String agentJar = \"/path/to/agent.jar\";\n    String bootJar = \"/path/to/boot.jar\";\n\n    Client client =\n        new Client(\n            2020,\n            null,\n            \".\",\n            false,\n            false,\n            false,\n            false,\n            null,\n            null,\n            agentJar,\n            bootJar);\n\n    // Use reflection to verify private fields (since they're not exposed)\n    try {\n      Field agentField = Client.class.getDeclaredField(\"agentJarOverride\");\n      agentField.setAccessible(true);\n      assertEquals(agentJar, agentField.get(client));\n\n      Field bootField = Client.class.getDeclaredField(\"bootJarOverride\");\n      bootField.setAccessible(true);\n      assertEquals(bootJar, bootField.get(client));\n    } catch (Exception e) {\n      fail(\"Failed to access private fields: \" + e.getMessage());\n    }\n  }\n\n  @Test\n  void testConstructorWithNullOverrides() {\n    Client client =\n        new Client(\n            2020, null, \".\", false, false, false, false, null, null, null, null);\n\n    try {\n      Field agentField = Client.class.getDeclaredField(\"agentJarOverride\");\n      agentField.setAccessible(true);\n      assertNull(agentField.get(client));\n\n      Field bootField = Client.class.getDeclaredField(\"bootJarOverride\");\n      bootField.setAccessible(true);\n      assertNull(bootField.get(client));\n    } catch (Exception e) {\n      fail(\"Failed to access private fields: \" + e.getMessage());\n    }\n  }\n\n  @Test\n  void testExtractEmbeddedAgentJarNotFound() throws Exception {\n    // Create a regular JAR without embedded JARs\n    File regularJar = tempDir.resolve(\"regular.jar\").toFile();\n    try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(regularJar))) {\n      JarEntry entry = new JarEntry(\"some/Class.class\");\n      jos.putNextEntry(entry);\n      jos.write(new byte[0]);\n      jos.closeEntry();\n    }\n\n    // This test would need to mock the Client.class location\n    // For now, we just verify the JAR exists\n    assertTrue(regularJar.exists());\n  }\n\n  @Test\n  void testUberJarCreation() throws Exception {\n    File uberJar = createUberJar();\n    assertTrue(uberJar.exists());\n\n    // Verify embedded JARs exist\n    try (JarFile jar = new JarFile(uberJar)) {\n      assertNotNull(jar.getJarEntry(\"META-INF/embedded/btrace-agent.jar\"));\n      assertNotNull(jar.getJarEntry(\"META-INF/embedded/btrace-boot.jar\"));\n    }\n  }\n\n  @Test\n  void testAgentJarOverrideTakesPrecedence() {\n    // When agentJarOverride is set, it should be used instead of discovery\n    String overridePath = \"/custom/path/btrace-agent.jar\";\n\n    Client client =\n        new Client(2020, null, \".\", false, false, false, false, null, null, overridePath, null);\n\n    try {\n      Field agentField = Client.class.getDeclaredField(\"agentJarOverride\");\n      agentField.setAccessible(true);\n      assertEquals(overridePath, agentField.get(client));\n    } catch (Exception e) {\n      fail(\"Failed to verify agentJarOverride: \" + e.getMessage());\n    }\n  }\n\n  @Test\n  void testBootJarOverridePrependsToBootCp() {\n    // Boot JAR override should be prepended to boot classpath\n    String bootOverride = \"/custom/boot.jar\";\n\n    Client client =\n        new Client(2020, null, \".\", false, false, false, false, null, null, null, bootOverride);\n\n    try {\n      Field bootField = Client.class.getDeclaredField(\"bootJarOverride\");\n      bootField.setAccessible(true);\n      assertEquals(bootOverride, bootField.get(client));\n    } catch (Exception e) {\n      fail(\"Failed to verify bootJarOverride: \" + e.getMessage());\n    }\n  }\n\n  @Test\n  void testBackwardCompatibility() {\n    // Old constructor should still work (no overrides)\n    Client client = new Client(2020, null, \".\", false, false, false, false, null, null);\n\n    try {\n      Field agentField = Client.class.getDeclaredField(\"agentJarOverride\");\n      agentField.setAccessible(true);\n      assertNull(agentField.get(client));\n\n      Field bootField = Client.class.getDeclaredField(\"bootJarOverride\");\n      bootField.setAccessible(true);\n      assertNull(bootField.get(client));\n    } catch (Exception e) {\n      fail(\"Failed to verify backward compatibility: \" + e.getMessage());\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-client/src/test/java/org/openjdk/btrace/client/MainTest.java",
    "content": "package org.openjdk.btrace.client;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nclass MainTest {\n\n  @TempDir Path tempDir;\n\n  /**\n   * Creates a mock uber JAR with embedded agent and boot JARs for testing extraction.\n   */\n  private File createTestUberJar() throws IOException {\n    File uberJar = tempDir.resolve(\"btrace-test.jar\").toFile();\n\n    try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(uberJar))) {\n      // Add embedded agent JAR\n      JarEntry agentEntry = new JarEntry(\"META-INF/embedded/btrace-agent.jar\");\n      jos.putNextEntry(agentEntry);\n      jos.write(\"test agent jar content\".getBytes());\n      jos.closeEntry();\n\n      // Add embedded boot JAR\n      JarEntry bootEntry = new JarEntry(\"META-INF/embedded/btrace-boot.jar\");\n      jos.putNextEntry(bootEntry);\n      jos.write(\"test boot jar content\".getBytes());\n      jos.closeEntry();\n    }\n\n    return uberJar;\n  }\n\n  @Test\n  void testExtractJar() throws Exception {\n    File sourceJar = createTestUberJar();\n    File targetFile = tempDir.resolve(\"extracted.jar\").toFile();\n\n    // Use reflection to access private extractJar method\n    Method extractJarMethod =\n        Main.class.getDeclaredMethod(\n            \"extractJar\", JarFile.class, String.class, File.class);\n    extractJarMethod.setAccessible(true);\n\n    try (JarFile jarFile = new JarFile(sourceJar)) {\n      extractJarMethod.invoke(null, jarFile, \"META-INF/embedded/btrace-agent.jar\", targetFile);\n    }\n\n    // Verify extraction\n    assertTrue(targetFile.exists());\n    assertTrue(targetFile.length() > 0);\n\n    // Verify content\n    byte[] content = Files.readAllBytes(targetFile.toPath());\n    assertEquals(\"test agent jar content\", new String(content));\n  }\n\n  @Test\n  void testExtractJarMissingEntry() throws Exception {\n    File sourceJar = createTestUberJar();\n    File targetFile = tempDir.resolve(\"extracted.jar\").toFile();\n\n    Method extractJarMethod =\n        Main.class.getDeclaredMethod(\n            \"extractJar\", JarFile.class, String.class, File.class);\n    extractJarMethod.setAccessible(true);\n\n    try (JarFile jarFile = new JarFile(sourceJar)) {\n      Exception exception =\n          assertThrows(\n              Exception.class,\n              () -> {\n                extractJarMethod.invoke(\n                    null, jarFile, \"META-INF/embedded/nonexistent.jar\", targetFile);\n              });\n\n      Throwable cause = exception.getCause();\n      assertTrue(cause instanceof IOException, \"Expected IOException as cause\");\n      assertTrue(\n          cause.getMessage().contains(\"Embedded JAR not found\"),\n          \"Expected error message about missing embedded JAR\");\n    }\n  }\n\n  @Test\n  void testExtractJarToDirectory() throws Exception {\n    File sourceJar = createTestUberJar();\n    File outputDir = tempDir.resolve(\"output\").toFile();\n    assertTrue(outputDir.mkdirs());\n\n    File agentFile = new File(outputDir, \"btrace-agent.jar\");\n    File bootFile = new File(outputDir, \"btrace-boot.jar\");\n\n    Method extractJarMethod =\n        Main.class.getDeclaredMethod(\n            \"extractJar\", JarFile.class, String.class, File.class);\n    extractJarMethod.setAccessible(true);\n\n    try (JarFile jarFile = new JarFile(sourceJar)) {\n      extractJarMethod.invoke(null, jarFile, \"META-INF/embedded/btrace-agent.jar\", agentFile);\n      extractJarMethod.invoke(null, jarFile, \"META-INF/embedded/btrace-boot.jar\", bootFile);\n    }\n\n    // Verify both files were extracted\n    assertTrue(agentFile.exists());\n    assertTrue(bootFile.exists());\n    assertTrue(agentFile.length() > 0);\n    assertTrue(bootFile.length() > 0);\n  }\n\n  @Test\n  void testExtractAgentCreatesDirectory() throws Exception {\n    File nonExistentDir = tempDir.resolve(\"newdir\").toFile();\n    assertFalse(nonExistentDir.exists());\n\n    // Test that handleExtractAgent would create the directory\n    // This is tested indirectly by verifying directory creation logic\n    assertTrue(nonExistentDir.mkdirs() || nonExistentDir.exists());\n    assertTrue(nonExistentDir.exists());\n    assertTrue(nonExistentDir.isDirectory());\n  }\n\n  @Test\n  void testCLIFlagsParsing() throws Exception {\n    // Test that static fields can be set (simulating CLI flag parsing)\n    // This verifies the fields exist and are accessible for setting\n\n    Field agentJarField = Main.class.getDeclaredField(\"AGENT_JAR_OVERRIDE\");\n    agentJarField.setAccessible(true);\n    assertNotNull(agentJarField);\n\n    Field bootJarField = Main.class.getDeclaredField(\"BOOT_JAR_OVERRIDE\");\n    bootJarField.setAccessible(true);\n    assertNotNull(bootJarField);\n\n    Field extractDirField = Main.class.getDeclaredField(\"EXTRACT_AGENT_DIR\");\n    extractDirField.setAccessible(true);\n    assertNotNull(extractDirField);\n  }\n\n  @Test\n  void testExtractJarWithLargeContent() throws Exception {\n    // Create a JAR with larger content to test buffer handling\n    File sourceJar = tempDir.resolve(\"large-btrace.jar\").toFile();\n    byte[] largeContent = new byte[16384]; // 16KB\n    for (int i = 0; i < largeContent.length; i++) {\n      largeContent[i] = (byte) (i % 256);\n    }\n\n    try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(sourceJar))) {\n      JarEntry entry = new JarEntry(\"META-INF/embedded/btrace-agent.jar\");\n      jos.putNextEntry(entry);\n      jos.write(largeContent);\n      jos.closeEntry();\n    }\n\n    File targetFile = tempDir.resolve(\"extracted-large.jar\").toFile();\n\n    Method extractJarMethod =\n        Main.class.getDeclaredMethod(\n            \"extractJar\", JarFile.class, String.class, File.class);\n    extractJarMethod.setAccessible(true);\n\n    try (JarFile jarFile = new JarFile(sourceJar)) {\n      extractJarMethod.invoke(null, jarFile, \"META-INF/embedded/btrace-agent.jar\", targetFile);\n    }\n\n    // Verify complete extraction\n    assertTrue(targetFile.exists());\n    assertEquals(largeContent.length, targetFile.length());\n\n    // Verify content integrity\n    byte[] extractedContent = Files.readAllBytes(targetFile.toPath());\n    assertArrayEquals(largeContent, extractedContent);\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/build.gradle",
    "content": "dependencies {\n    implementation libs.slf4j\n    implementation libs.slf4j.simple\n    implementation libs.asm\n    implementation libs.asm.util\n\n    def toolsJar = getToolsJar();\n    if (toolsJar.getAsFile().exists()) {\n        runtimeOnly files(\"${toolsJar}\")\n    }\n    implementation project(path: ':btrace-core')\n    implementation project(path: ':btrace-runtime')\n    implementation project(path: ':btrace-boot')\n    runtimeOnly project(path: ':btrace-instr')\n\n    testImplementation project(path: ':btrace-instr')\n    testImplementation project(path: ':btrace-extensions:btrace-metrics')\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/AnnotationSerializer.java",
    "content": "package org.openjdk.btrace.compiler;\n\nimport org.objectweb.asm.tree.AnnotationNode;\n\npublic class AnnotationSerializer {\n  public static void serialize(AnnotationNode an, StringBuilder sb) {\n    sb.append(\"{type:\").append(an.desc).append(',');\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/ClassDataJavaFileObject.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.compiler;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.Reader;\nimport java.io.Writer;\nimport java.net.URI;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.NestingKind;\nimport javax.tools.JavaFileObject;\n\n/**\n * A JavaFileObject that reads class bytecode from .classdata files in a masked JAR.\n * <p>\n * This is used by MaskedJavaFileManager to provide javac with access to annotation\n * classes stored as .classdata files instead of .class files.\n *\n * @author Jaroslav Bachorik\n */\nclass ClassDataJavaFileObject implements JavaFileObject {\n    private final String className;\n    private final JarFile jarFile;\n    private final JarEntry entry;\n    private final String entryName;\n    private final URI uri;\n\n    /**\n     * Creates a new ClassDataJavaFileObject.\n     *\n     * @param className the fully qualified class name (e.g., \"org.example.MyClass\")\n     * @param jarFile   the JAR file containing the .classdata file\n     * @param entry     the JAR entry for the .classdata file\n     */\n    ClassDataJavaFileObject(String className, JarFile jarFile, JarEntry entry) {\n        String name = entry.getName();\n        if (name.contains(\"..\")) {\n            throw new IllegalArgumentException(\"Invalid entry name (path traversal): \" + name);\n        }\n        this.className = className;\n        this.jarFile = jarFile;\n        this.entry = entry;\n        this.entryName = name;\n        this.uri = URI.create(\"jar:file:\" + jarFile.getName() + \"!/\" + name);\n    }\n\n    @Override\n    public Kind getKind() {\n        return Kind.CLASS;\n    }\n\n    @Override\n    public boolean isNameCompatible(String simpleName, Kind kind) {\n        if (kind != Kind.CLASS) {\n            return false;\n        }\n        String baseName = simpleName + \".class\";\n        return className.equals(simpleName) || className.endsWith(\".\" + simpleName);\n    }\n\n    @Override\n    public NestingKind getNestingKind() {\n        return null; // Unknown\n    }\n\n    @Override\n    public Modifier getAccessLevel() {\n        return null; // Unknown\n    }\n\n    @Override\n    public URI toUri() {\n        return uri;\n    }\n\n    @Override\n    public String getName() {\n        // Return a .class name instead of .classdata for javac compatibility\n        if (entryName.endsWith(\".classdata\")) {\n            return entryName.substring(0, entryName.length() - \".classdata\".length()) + \".class\";\n        }\n        return entryName;\n    }\n\n    @Override\n    public InputStream openInputStream() throws IOException {\n        return jarFile.getInputStream(entry);\n    }\n\n    @Override\n    public OutputStream openOutputStream() throws IOException {\n        throw new UnsupportedOperationException(\"Cannot write to .classdata file\");\n    }\n\n    @Override\n    public Reader openReader(boolean ignoreEncodingErrors) throws IOException {\n        throw new UnsupportedOperationException(\"Cannot read .classdata as text\");\n    }\n\n    @Override\n    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {\n        throw new UnsupportedOperationException(\"Cannot read .classdata as text\");\n    }\n\n    @Override\n    public Writer openWriter() throws IOException {\n        throw new UnsupportedOperationException(\"Cannot write to .classdata file\");\n    }\n\n    @Override\n    public long getLastModified() {\n        return entry.getTime();\n    }\n\n    @Override\n    public boolean delete() {\n        return false;\n    }\n\n    /**\n     * Reads the entire .classdata file into a byte array.\n     *\n     * @return the class bytecode\n     * @throws IOException if reading fails\n     */\n    byte[] getClassBytes() throws IOException {\n        try (InputStream is = openInputStream()) {\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            byte[] buffer = new byte[8192];\n            int bytesRead;\n            while ((bytesRead = is.read(buffer)) != -1) {\n                baos.write(buffer, 0, bytesRead);\n            }\n            return baos.toByteArray();\n        }\n    }\n\n    /**\n     * Infers the binary name (fully qualified class name) from this file object.\n     *\n     * @return the binary name (e.g., \"org.openjdk.btrace.core.annotations.BTrace\")\n     */\n    String inferBinaryName() {\n        return className;\n    }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/Compiler.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.compiler;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.Writer;\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport javax.tools.JavaCompiler;\nimport javax.tools.JavaFileObject;\nimport javax.tools.StandardJavaFileManager;\nimport javax.tools.ToolProvider;\nimport org.openjdk.btrace.core.Messages;\nimport org.openjdk.btrace.runtime.BTraceRuntimeAccess;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Compiler for a BTrace program. Note that a BTrace program is a Java program that is specially\n * annotated and can *not* use many Java constructs (essentially java--). We use JSR 199 API to\n * compile BTrace program but validate the program (for BTrace safety rules) using JSR 269 and\n * javac's Tree API.\n *\n * @author A. Sundararajan\n */\npublic class Compiler {\n  private static final Logger log = LoggerFactory.getLogger(Compiler.class);\n\n  private final CompilerHelper compilerHelper;\n  // null means no preprocessing isf done.\n  public List<String> includeDirs;\n  private final StandardJavaFileManager stdManager;\n  private final String packExtension = \"class\";\n\n  public Compiler(String includePath, boolean generatePack) {\n    if (includePath != null) {\n      includeDirs = new ArrayList<>();\n      String[] paths = includePath.split(File.pathSeparator);\n      includeDirs.addAll(Arrays.asList(paths));\n    }\n    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();\n    stdManager = compiler.getStandardFileManager(null, null, null);\n    compilerHelper = new CompilerHelper(compiler, generatePack);\n  }\n\n  public Compiler(String includePath) {\n    this(includePath, false);\n  }\n\n  public Compiler(boolean generatePack) {\n    this(null, generatePack);\n  }\n\n  public Compiler() {\n    this(null);\n  }\n\n  private static void usage(String msg) {\n    System.err.println(msg);\n    System.exit(1);\n  }\n\n  private static void usage() {\n    usage(Messages.get(\"btracec.usage\"));\n  }\n\n  // simple test main\n  @SuppressWarnings({\"DefaultCharset\", \"RedundantThrows\"})\n  public static void main(String[] args) throws Exception {\n    if (args.length == 0) {\n      usage();\n    }\n\n    // turn off the unique client name generation as it is undesired during compilation\n    try {\n      Field f = BTraceRuntimeAccess.class.getDeclaredField(\"uniqueClientClassNames\");\n      f.setAccessible(true);\n      f.set(null, false);\n    } catch (Exception ignored) {\n    }\n\n    String classPath = \".\";\n    String outputDir = \".\";\n    String includePath = null;\n    boolean trusted = false;\n    boolean generatePack = true;\n    String packExtension = null;\n    int count = 0;\n    boolean classPathDefined = false;\n    boolean outputDirDefined = false;\n    boolean includePathDefined = false;\n    boolean trustedDefined = false;\n\n    for (; ; ) {\n      if (args[count].charAt(0) == '-') {\n        if (args.length <= count + 1) {\n          usage();\n        }\n        if ((args[count].equals(\"-cp\") || args[count].equals(\"-classpath\")) && !classPathDefined) {\n          classPath = args[++count];\n          classPathDefined = true;\n        } else if (args[count].equals(\"-d\") && !outputDirDefined) {\n          outputDir = args[++count];\n          outputDirDefined = true;\n        } else if (args[count].equals(\"-I\") && !includePathDefined) {\n          includePath = args[++count];\n          includePathDefined = true;\n        } else if ((args[count].equals(\"-unsafe\") || args[count].equals(\"-trusted\"))\n            && !trustedDefined) {\n          trusted = true;\n          trustedDefined = true;\n        } else if (args[count].equals(\"-nopack\")) {\n          generatePack = false;\n        } else if (args[count].equals(\"-packext\")) {\n          packExtension = args[++count];\n        } else {\n          usage();\n        }\n        count++;\n        if (count >= args.length) {\n          break;\n        }\n      } else {\n        break;\n      }\n    }\n\n    if (args.length <= count) {\n      usage();\n    }\n\n    if (!generatePack && packExtension != null) {\n      usage(\"Can not specify pack extension if not using packs (-nopack)\");\n    }\n\n    File[] files = new File[args.length - count];\n    for (int i = 0; i < files.length; i++) {\n      files[i] = new File(args[i + count]);\n      if (!files[i].exists()) {\n        usage(\"File not found: \" + files[i]);\n      }\n    }\n\n    Compiler compiler = new Compiler(includePath, generatePack);\n    classPath += File.pathSeparator + System.getProperty(\"java.class.path\");\n    try {\n      Map<String, byte[]> classes =\n          compiler.compile(files, new PrintWriter(System.err), \".\", classPath);\n      if (classes != null) {\n        // write .class files.\n        for (Map.Entry<String, byte[]> c : classes.entrySet()) {\n          String name = c.getKey().replace(\".\", File.separator);\n          int index = name.lastIndexOf(File.separatorChar);\n          String dir = outputDir + File.separator;\n          if (index != -1) {\n            dir += name.substring(0, index);\n          }\n          new File(dir).mkdirs();\n          String file;\n          if (index != -1) {\n            file = name.substring(index + 1);\n          } else {\n            file = name;\n          }\n          file += \".\" + (packExtension != null ? packExtension : \"class\");\n          File out = new File(dir, file);\n          try (FileOutputStream fos = new FileOutputStream(out)) {\n            fos.write(c.getValue());\n          }\n        }\n      } else {\n        // fail\n        System.exit(1);\n      }\n    } catch (Throwable t) {\n      log.error(\"Compiler invocation failed\", t);\n      System.err.println(\"ERROR: Compiler failed: \" + t.getMessage());\n      // fail\n      System.exit(1);\n    }\n  }\n\n  public Map<String, byte[]> compile(\n      String fileName, String source, Writer err, String sourcePath, String classPath) {\n    // create a new memory JavaFileManager\n    MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager, includeDirs);\n\n    // prepare the compilation unit\n    List<JavaFileObject> compUnits = new ArrayList<>(1);\n    compUnits.add(MemoryJavaFileManager.makeStringSource(fileName, source, includeDirs));\n    return compile(manager, compUnits, err, sourcePath, classPath);\n  }\n\n  public Map<String, byte[]> compile(File file, Writer err, String sourcePath, String classPath) {\n    File[] files = new File[1];\n    files[0] = file;\n    return compile(files, err, sourcePath, classPath);\n  }\n\n  public Map<String, byte[]> compile(\n      File[] files, Writer err, String sourcePath, String classPath) {\n    Iterable<? extends JavaFileObject> compUnits = stdManager.getJavaFileObjects(files);\n    List<JavaFileObject> preprocessedCompUnits = new ArrayList<>();\n    try {\n      for (JavaFileObject jfo : compUnits) {\n        preprocessedCompUnits.add(MemoryJavaFileManager.preprocessedFileObject(jfo, includeDirs));\n      }\n    } catch (IOException ioExp) {\n      throw new RuntimeException(ioExp);\n    }\n    return compile(preprocessedCompUnits, err, sourcePath, classPath);\n  }\n\n  public Map<String, byte[]> compile(\n      Iterable<? extends JavaFileObject> compUnits,\n      Writer err,\n      String sourcePath,\n      String classPath) {\n    // create a new memory JavaFileManager\n    MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager, includeDirs);\n    return compilerHelper.compile(manager, compUnits, err, sourcePath, classPath);\n  }\n\n  private Map<String, byte[]> compile(\n      MemoryJavaFileManager manager,\n      Iterable<? extends JavaFileObject> compUnits,\n      Writer err,\n      String sourcePath,\n      String classPath) {\n    // to collect errors, warnings etc.\n\n    // javac options\n\n    // create a compilation task\n\n    // we add BTrace Verifier as a (JSR 269) Processor\n\n    // print dignostics messages in case of failures.\n\n    // collect .class bytes of all compiled classes\n    return compilerHelper.compile(manager, compUnits, err, sourcePath, classPath);\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/CompilerClassWriter.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.compiler;\n\nimport java.io.File;\nimport java.io.PrintWriter;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.objectweb.asm.ClassWriter;\n\n/**\n * @author Jaroslav Bachorik\n */\nclass CompilerClassWriter extends ClassWriter {\n  private final ClassLoader cl;\n\n  public CompilerClassWriter(String classPath, PrintWriter perr) {\n    this(classPath, perr, null);\n  }\n\n  public CompilerClassWriter(String classPath, PrintWriter perr, ClassLoader maskedClassLoader) {\n    super(ClassWriter.COMPUTE_FRAMES);\n    if (maskedClassLoader != null) {\n      // Use the provided MaskedClassLoader which can read .classdata files\n      this.cl = maskedClassLoader;\n    } else {\n      // Fall back to URLClassLoader for standard .class files\n      List<URL> urls = new ArrayList<>();\n      if (classPath != null) {\n        for (String e : classPath.split(File.pathSeparator)) {\n          File f = new File(e);\n          try {\n            urls.add(f.toURI().toURL());\n          } catch (MalformedURLException ex) {\n            perr.printf(\"%s is not a valid classpath entry\\n\", e);\n          }\n        }\n      }\n      this.cl = new URLClassLoader(urls.toArray(new URL[0]), getClass().getClassLoader());\n    }\n  }\n\n  @Override\n  protected String getCommonSuperClass(String type1, String type2) {\n    Class<?> c, d;\n    try {\n      c = cl.loadClass(type1.replace('/', '.'));\n      d = cl.loadClass(type2.replace('/', '.'));\n    } catch (Exception e) {\n      throw new RuntimeException(e.toString());\n    }\n    if (c.isAssignableFrom(d)) {\n      return type1;\n    }\n    if (d.isAssignableFrom(c)) {\n      return type2;\n    }\n    if (c.isInterface() || d.isInterface()) {\n      return \"java/lang/Object\";\n    } else {\n      do {\n        c = c.getSuperclass();\n      } while (!c.isAssignableFrom(d));\n      return c.getName().replace('.', '/');\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/CompilerHelper.java",
    "content": "package org.openjdk.btrace.compiler;\n\nimport com.sun.source.util.JavacTask;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.PrintWriter;\nimport java.io.Writer;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.file.DirectoryStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.ServiceLoader;\nimport javax.annotation.processing.Processor;\nimport javax.tools.Diagnostic;\nimport javax.tools.Diagnostic.Kind;\nimport javax.tools.DiagnosticCollector;\nimport javax.tools.JavaCompiler;\nimport javax.tools.JavaFileObject;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassWriter;\nimport org.openjdk.btrace.boot.MaskedClassLoader;\nimport org.openjdk.btrace.boot.MaskedJarUtils;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nclass CompilerHelper {\n  private static final Logger log = LoggerFactory.getLogger(CompilerHelper.class);\n  private final boolean generatePack;\n\n  // JSR 199 compiler\n  private final JavaCompiler compiler;\n\n  CompilerHelper(JavaCompiler compiler, boolean generatePack) {\n    this.compiler = compiler;\n    this.generatePack = generatePack;\n  }\n\n  /**\n   * Extends the classpath with JARs from extension directories.\n   * Scans in order: BTRACE_HOME/libs/ext/, ~/.btrace/ext/, $BTRACE_EXT_PATH\n   *\n   * @param classPath original classpath (may be null)\n   * @return extended classpath including extension JARs\n   */\n  private String extendClassPathWithExtensions(String classPath) {\n    List<String> extensionJars = new ArrayList<>();\n\n    // 1. Built-in extensions: BTRACE_HOME/libs/ext/\n    String btraceHome = getBTraceHome();\n    if (btraceHome != null) {\n      Path builtinExtPath = Paths.get(btraceHome, \"libs\", \"ext\");\n      addExtensionJars(builtinExtPath, extensionJars);\n    }\n\n    // 2. User extensions: ~/.btrace/ext/\n    String userHome = System.getProperty(\"user.home\");\n    if (userHome != null) {\n      Path userExtPath = Paths.get(userHome, \".btrace\", \"ext\");\n      addExtensionJars(userExtPath, extensionJars);\n    }\n\n    // 3. Environment variable: BTRACE_EXT_PATH\n    String extPath = System.getenv(\"BTRACE_EXT_PATH\");\n    if (extPath != null && !extPath.isEmpty()) {\n      String[] paths = extPath.split(File.pathSeparator);\n      for (String path : paths) {\n        addExtensionJars(Paths.get(path), extensionJars);\n      }\n    }\n\n    // Combine with original classpath\n    if (extensionJars.isEmpty()) {\n      return classPath;\n    }\n\n    StringBuilder sb = new StringBuilder();\n    if (classPath != null && !classPath.isEmpty()) {\n      sb.append(classPath);\n    }\n\n    for (String jar : extensionJars) {\n      if (sb.length() > 0) {\n        sb.append(File.pathSeparator);\n      }\n      sb.append(jar);\n    }\n\n    return sb.toString();\n  }\n\n  /**\n   * Attempts to determine BTRACE_HOME from environment or compiler classpath.\n   *\n   * @return BTRACE_HOME path, or null if not found\n   */\n  private String getBTraceHome() {\n    // Try environment variable first\n    String envHome = System.getenv(\"BTRACE_HOME\");\n    if (envHome != null && Files.isDirectory(Paths.get(envHome))) {\n      return envHome;\n    }\n\n    // Try to find from compiler classpath (look for btrace-compiler.jar or btrace-boot.jar)\n    String classPath = System.getProperty(\"java.class.path\");\n    if (classPath != null) {\n      for (String entry : classPath.split(File.pathSeparator)) {\n        if (entry.contains(\"btrace-compiler\") || entry.contains(\"btrace-boot\")) {\n          File jarFile = new File(entry);\n          if (jarFile.exists()) {\n            File libsDir = jarFile.getParentFile();\n            if (libsDir != null && libsDir.getName().equals(\"libs\")) {\n              File home = libsDir.getParentFile();\n              if (home != null && home.isDirectory()) {\n                return home.getAbsolutePath();\n              }\n            }\n          }\n        }\n      }\n    }\n\n    return null;\n  }\n\n  /**\n   * Adds all JAR files from the given directory to the list.\n   *\n   * @param directory directory to scan\n   * @param jars list to add JAR paths to\n   */\n  private void addExtensionJars(Path directory, List<String> jars) {\n    if (!Files.isDirectory(directory)) {\n      return;\n    }\n\n    try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory, \"*.jar\")) {\n      for (Path jar : stream) {\n        jars.add(jar.toAbsolutePath().toString());\n      }\n    } catch (IOException ignored) {\n      // Directory not accessible, skip silently\n    }\n  }\n\n  Map<String, byte[]> compile(\n      MemoryJavaFileManager manager,\n      Iterable<? extends JavaFileObject> compUnits,\n      Writer err,\n      String sourcePath,\n      String classPath) {\n    // Extend classpath with extension JARs\n    classPath = extendClassPathWithExtensions(classPath);\n\n    // to collect errors, warnings etc.\n    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();\n\n    // javac options\n    List<String> options = new ArrayList<>();\n    options.add(\"-Xlint:all\");\n    options.add(\"-g:lines\");\n    options.add(\"-deprecation\");\n    options.add(\"-source\");\n    options.add(\"8\");\n    options.add(\"-target\");\n    options.add(\"8\");\n    if (sourcePath != null) {\n      options.add(\"-sourcepath\");\n      options.add(sourcePath);\n    }\n\n    if (classPath != null) {\n      options.add(\"-classpath\");\n      options.add(classPath);\n    }\n\n    // Wrap the file manager with MaskedJavaFileManager if a masked JAR is on the classpath\n    javax.tools.JavaFileManager effectiveManager = manager;\n    File maskedJar = MaskedJarUtils.findMaskedJarInClasspath(classPath);\n    ClassLoader maskedClassLoader = null;\n    if (maskedJar != null) {\n      try {\n        effectiveManager = new MaskedJavaFileManager(manager, maskedJar);\n        log.debug(\"Using MaskedJavaFileManager for: {}\", maskedJar.getAbsolutePath());\n        // Create a MaskedClassLoader for CompilerClassWriter to use\n        maskedClassLoader = new MaskedClassLoader(maskedJar, \"client\", getClass().getClassLoader());\n      } catch (IOException e) {\n        log.warn(\"Failed to create MaskedJavaFileManager, falling back to standard manager\", e);\n      }\n    }\n\n    // create a compilation task\n    JavacTask task =\n        (JavacTask) compiler.getTask(err, effectiveManager, diagnostics, options, null, compUnits);\n    Verifier btraceVerifier = new Verifier();\n    task.setTaskListener(btraceVerifier);\n\n    // we add BTrace Verifier as a (JSR 269) Processor\n    List<Processor> processors = new ArrayList<>(1);\n    processors.add(btraceVerifier);\n    task.setProcessors(processors);\n\n    PrintWriter perr = (err instanceof PrintWriter) ? (PrintWriter) err : new PrintWriter(err);\n\n    // print dignostics messages in case of failures.\n    if (!task.call() || containsErrors(diagnostics)) {\n      for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {\n        printDiagnostic(diagnostic, perr);\n      }\n      perr.flush();\n      return null;\n    }\n\n    // collect .class bytes of all compiled classes\n    Map<String, byte[]> result = new HashMap<>();\n    try {\n      Map<String, byte[]> classBytes = manager.getClassBytes();\n      List<String> classNames = btraceVerifier.getClassNames();\n      for (String name : classNames) {\n        if (classBytes.containsKey(name)) {\n          dump(name + \"_before\", classBytes.get(name));\n          ClassReader cr = new ClassReader(classBytes.get(name));\n          ClassWriter cw = new CompilerClassWriter(classPath, perr, maskedClassLoader);\n          cr.accept(new Postprocessor(cw), ClassReader.EXPAND_FRAMES + ClassReader.SKIP_DEBUG);\n          byte[] classData = cw.toByteArray();\n          dump(name + \"_after\", classData);\n          if (generatePack) {\n            // temp hack; need turn off verifier\n            SharedSettings.GLOBAL.setTrusted(true);\n\n            String[] pathElements = classPath.split(File.pathSeparator);\n            List<URL> urlElements = new ArrayList<>(pathElements.length);\n\n            for (String pathElement : pathElements) {\n              File f = new File(pathElement);\n              urlElements.add(f.toURI().toURL());\n            }\n            URLClassLoader generatorCL =\n                new URLClassLoader(\n                    urlElements.toArray(new URL[0]), Compiler.class.getClassLoader());\n            ServiceLoader<PackGenerator> generators =\n                ServiceLoader.load(PackGenerator.class, generatorCL);\n            Iterator<PackGenerator> iter = generators.iterator();\n            if (iter.hasNext()) {\n              PackGenerator generator = iter.next();\n              SharedSettings.GLOBAL.setBootClassPath(classPath);\n              classData = generator.generateProbePack(classData);\n            }\n          }\n          result.put(name, classData);\n        }\n      }\n    } catch (IOException e) {\n      log.error(\"Compilation failed\", e);\n      perr.append(\"ERROR: Compilation failed: \").append(e.getMessage()).append(\"\\n\");\n    } finally {\n      // Close masked resources first (they wrap/depend on the base manager)\n      if (maskedClassLoader instanceof AutoCloseable) {\n        try {\n          ((AutoCloseable) maskedClassLoader).close();\n        } catch (Exception ignored) {\n        }\n      }\n      if (effectiveManager != manager) {\n        try {\n          effectiveManager.close();\n        } catch (IOException ignored) {\n        }\n      }\n      try {\n        manager.close();\n      } catch (IOException ignored) {\n      }\n    }\n    return result;\n  }\n\n  private void dump(String name, byte[] code) {\n    OutputStream os = null;\n    try {\n      name = name.replace(\".\", \"_\") + \".class\";\n      File f = new File(System.getProperty(\"java.io.tmpdir\"), name);\n      if (!f.exists()) {\n        f.getParentFile().createNewFile();\n      }\n      os = new FileOutputStream(f);\n      os.write(code);\n    } catch (IOException ignored) {\n\n    } finally {\n      if (os != null) {\n        try {\n          os.close();\n        } catch (IOException ignored) {\n        }\n      }\n    }\n  }\n\n  private void printDiagnostic(Diagnostic diagnostic, PrintWriter perr) {\n    perr.println(diagnostic);\n  }\n\n  /**\n   * Checks if the list of diagnostic messages contains at least one error. Certain {@link\n   * JavacTask} implementations may return success error code even though errors were reported.\n   */\n  private boolean containsErrors(DiagnosticCollector<?> diagnostics) {\n    for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics()) {\n      if (diagnostic.getKind() == Kind.ERROR) {\n        return true;\n      }\n    }\n    return false;\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/ConcatenatingReader.java",
    "content": "/*\n * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistribution of source code must retain the above copyright\n *   notice, this list of conditions and the following disclaimer.\n *\n * - Redistribution in binary form must reproduce the above copyright\n *   notice, this list of conditions and the following disclaimer in the\n *   documentation and/or other materials provided with the distribution.\n *\n * Neither the name of Sun Microsystems, Inc. or the names of\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * This software is provided \"AS IS,\" without a warranty of any kind. ALL\n * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,\n * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A\n * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN\n * MICROSYSTEMS, INC. (\"SUN\") AND ITS LICENSORS SHALL NOT BE LIABLE FOR\n * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR\n * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR\n * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR\n * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE\n * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,\n * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF\n * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n *\n * You acknowledge that this software is not designed or intended for use\n * in the design, construction, operation or maintenance of any nuclear\n * facility.\n *\n * Sun gratefully acknowledges that this software was originally authored\n * and developed by Kenneth Bradley Russell and Christopher John Kline.\n */\npackage org.openjdk.btrace.compiler;\n\nimport java.io.BufferedReader;\nimport java.io.FilterReader;\nimport java.io.IOException;\n\n/**\n * This code is based on PCPP code from the GlueGen project.\n *\n * <p>A Reader implementation which finds lines ending in the backslash character ('\\') and\n * concatenates them with the next line.\n *\n * @author Kenneth B. Russell (original author)\n * @author A. Sundararajan (changes documented below)\n *     <p>Changes:\n *     <p>* Changed the package name. * Formatted with NetBeans.\n */\npublic class ConcatenatingReader extends FilterReader {\n  private static final String NEW_LINE = System.getProperty(\"line.separator\");\n  private final BufferedReader inReader;\n  // Any leftover characters go here\n  private char[] curBuf;\n  private int curPos;\n\n  /**\n   * This class requires that the input reader be a BufferedReader so it can do line-oriented\n   * operations.\n   */\n  public ConcatenatingReader(BufferedReader in) {\n    super(in);\n    inReader = in;\n  }\n\n  @Override\n  public int read() throws IOException {\n    char[] tmp = new char[1];\n    int num = read(tmp, 0, 1);\n    if (num < 0) {\n      return -1;\n    }\n    return tmp[0];\n  }\n\n  // It's easier not to support mark/reset since we don't need it\n  @Override\n  public boolean markSupported() {\n    return false;\n  }\n\n  @Override\n  public void mark(int readAheadLimit) throws IOException {\n    throw new IOException(\"mark/reset not supported\");\n  }\n\n  @Override\n  public void reset() throws IOException {\n    throw new IOException(\"mark/reset not supported\");\n  }\n\n  @Override\n  public boolean ready() throws IOException {\n    return curBuf != null || inReader.ready();\n  }\n\n  @Override\n  public int read(char[] cbuf, int off, int len) throws IOException {\n    if (curBuf == null) {\n      nextLine();\n    }\n\n    if (curBuf == null) {\n      return -1;\n    }\n\n    int numRead = 0;\n\n    while ((len > 0) && (curBuf != null) && (curPos < curBuf.length)) {\n      cbuf[off] = curBuf[curPos];\n      ++curPos;\n      ++off;\n      --len;\n      ++numRead;\n      if (curPos == curBuf.length) {\n        nextLine();\n      }\n    }\n\n    return numRead;\n  }\n\n  @Override\n  public long skip(long n) throws IOException {\n    long numSkipped = 0;\n\n    while (n > 0) {\n      int intN = (int) n;\n      char[] tmp = new char[intN];\n      int numRead = read(tmp, 0, intN);\n      n -= numRead;\n      numSkipped += numRead;\n      if (numRead < intN) {\n        break;\n      }\n    }\n    return numSkipped;\n  }\n\n  private void nextLine() throws IOException {\n    String cur = inReader.readLine();\n    if (cur == null) {\n      curBuf = null;\n      return;\n    }\n    // The trailing newline was trimmed by the readLine() method. See\n    // whether we have to put it back or not, depending on whether the\n    // last character of the line is the concatenation character.\n    int numChars = cur.length();\n    boolean needNewline = true;\n    if ((numChars > 0) && (cur.charAt(cur.length() - 1) == '\\\\')) {\n      --numChars;\n      needNewline = false;\n    }\n    char[] buf = new char[numChars + (needNewline ? NEW_LINE.length() : 0)];\n    cur.getChars(0, numChars, buf, 0);\n    if (needNewline) {\n      NEW_LINE.getChars(0, NEW_LINE.length(), buf, numChars);\n    }\n    curBuf = buf;\n    curPos = 0;\n  }\n\n  // Test harness\n  /*\n  public static void main(String[] args) throws IOException {\n  if (args.length != 1) {\n  System.out.println(\"Usage: java ConcatenatingReader [file name]\");\n  System.exit(1);\n  }\n  ConcatenatingReader reader = new ConcatenatingReader(new BufferedReader(new FileReader(args[0])));\n  OutputStreamWriter writer = new OutputStreamWriter(System.out);\n  char[] buf = new char[8192];\n  boolean done = false;\n  while (!done && reader.ready()) {\n  int numRead = reader.read(buf, 0, buf.length);\n  writer.write(buf, 0, numRead);\n  if (numRead < buf.length)\n  done = true;\n  }\n  writer.flush();\n  }\n   */\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/MaskedJavaFileManager.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.compiler;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport javax.tools.FileObject;\nimport javax.tools.ForwardingJavaFileManager;\nimport javax.tools.JavaFileManager;\nimport javax.tools.JavaFileObject;\nimport javax.tools.JavaFileObject.Kind;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A JavaFileManager that can read .classdata files from a masked JAR.\n * <p>\n * This file manager wraps another JavaFileManager and intercepts requests for class files.\n * When javac requests a class file (e.g., to resolve an annotation), this manager first\n * checks if the class exists as a .classdata file in the masked JAR's shared section.\n * If found, it returns a ClassDataJavaFileObject that reads from the .classdata file.\n * Otherwise, it delegates to the wrapped file manager.\n * <p>\n * This allows javac to find and process annotation classes that are stored as .classdata\n * files instead of .class files.\n *\n * @author Jaroslav Bachorik\n */\nclass MaskedJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {\n    private static final Logger log = LoggerFactory.getLogger(MaskedJavaFileManager.class);\n    private static final boolean DEBUG = Boolean.getBoolean(\"btrace.compiler.debug\");\n\n    private final File maskedJarFile;\n    private final JarFile jarFile;\n\n    /**\n     * Creates a new MaskedJavaFileManager.\n     *\n     * @param fileManager the file manager to wrap\n     * @param maskedJar   the masked JAR file containing .classdata files\n     * @throws IOException if the JAR file cannot be opened\n     */\n    MaskedJavaFileManager(JavaFileManager fileManager, File maskedJar) throws IOException {\n        super(fileManager);\n        this.maskedJarFile = maskedJar;\n        this.jarFile = new JarFile(maskedJar);\n        debug(\"Created MaskedJavaFileManager for: \" + maskedJar.getAbsolutePath());\n    }\n\n    @Override\n    public JavaFileObject getJavaFileForInput(\n            Location location, String className, Kind kind) throws IOException {\n        debug(\"getJavaFileForInput: location=\" + location + \", className=\" + className + \", kind=\" + kind);\n\n        // Only intercept CLASS kind requests (not SOURCE)\n        if (kind == Kind.CLASS) {\n            // Check if this class exists as .classdata in the shared section\n            String classDataPath = \"META-INF/btrace/shared/\" + className.replace('.', '/') + \".classdata\";\n            JarEntry entry = jarFile.getJarEntry(classDataPath);\n\n            if (entry != null) {\n                debug(\"Found .classdata for: \" + className);\n                return new ClassDataJavaFileObject(className, jarFile, entry);\n            }\n        }\n\n        // Fall back to standard file manager\n        return super.getJavaFileForInput(location, className, kind);\n    }\n\n    @Override\n    public Iterable<JavaFileObject> list(\n            Location location,\n            String packageName,\n            Set<Kind> kinds,\n            boolean recurse)\n            throws IOException {\n        debug(\"list: location=\" + location + \", package=\" + packageName + \", kinds=\" + kinds);\n\n        // Get the standard list first\n        Iterable<JavaFileObject> standardFiles = super.list(location, packageName, kinds, recurse);\n\n        // If not looking for CLASS files, just return standard list\n        if (!kinds.contains(Kind.CLASS)) {\n            return standardFiles;\n        }\n\n        List<JavaFileObject> result = new ArrayList<>();\n        if (standardFiles != null) {\n            for (JavaFileObject jfo : standardFiles) {\n                result.add(jfo);\n            }\n        }\n\n        // Add .classdata files from the shared section for this package\n        String packagePath = packageName.replace('.', '/');\n        String sharedPackagePath = \"META-INF/btrace/shared/\" + packagePath;\n\n        Enumeration<JarEntry> entries = jarFile.entries();\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            String name = entry.getName();\n\n            // Check if this entry is in the requested package\n            if (name.startsWith(sharedPackagePath + \"/\") && name.endsWith(\".classdata\")) {\n                // Extract the simple name and check if it's a direct child (not recursive)\n                String relativePath = name.substring(sharedPackagePath.length() + 1);\n                boolean isDirectChild = !relativePath.substring(0, relativePath.lastIndexOf('.')).contains(\"/\");\n\n                if (recurse || isDirectChild) {\n                    // Convert path to class name\n                    String className = name.substring(\"META-INF/btrace/shared/\".length())\n                            .replace('/', '.')\n                            .replace(\".classdata\", \"\");\n                    debug(\"Found .classdata in list(): \" + className);\n                    result.add(new ClassDataJavaFileObject(className, jarFile, entry));\n                }\n            }\n        }\n\n        return result;\n    }\n\n    @Override\n    public String inferBinaryName(Location location, JavaFileObject file) {\n        // If it's our custom ClassDataJavaFileObject, we know the binary name\n        if (file instanceof ClassDataJavaFileObject) {\n            ClassDataJavaFileObject cdfo = (ClassDataJavaFileObject) file;\n            String binaryName = cdfo.inferBinaryName();\n            debug(\"inferBinaryName: \" + binaryName + \" for \" + file.getName());\n            return binaryName;\n        }\n\n        // Otherwise delegate to parent\n        return super.inferBinaryName(location, file);\n    }\n\n    @Override\n    public void close() throws IOException {\n        try {\n            jarFile.close();\n        } finally {\n            super.close();\n        }\n    }\n\n    private void debug(String msg) {\n        if (DEBUG) {\n            log.debug(\"[MaskedFileManager] {}\", msg);\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/MemoryJavaFileManager.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n/*\n * MemoryJavaFileManager.java\n * @author A. Sundararajan\n */\npackage org.openjdk.btrace.compiler;\n\nimport java.io.BufferedReader;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FilterOutputStream;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.net.URI;\nimport java.nio.CharBuffer;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport javax.tools.FileObject;\nimport javax.tools.ForwardingJavaFileManager;\nimport javax.tools.JavaFileManager;\nimport javax.tools.JavaFileObject;\nimport javax.tools.JavaFileObject.Kind;\nimport javax.tools.SimpleJavaFileObject;\n\n/**\n * JavaFileManager that keeps compiled .class bytes in memory. And also can expose input .java\n * \"files\" from Strings.\n *\n * @author A. Sundararajan\n */\n@SuppressWarnings(\"RedundantThrows\")\npublic final class MemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {\n\n  private final List<String> includeDirs;\n  private Map<String, byte[]> classBytes;\n\n  public MemoryJavaFileManager(JavaFileManager fileManager, List<String> includeDirs) {\n    super(fileManager);\n    this.includeDirs = includeDirs;\n    classBytes = new HashMap<>();\n  }\n\n  static JavaFileObject preprocessedFileObject(JavaFileObject fo, List<String> includeDirs)\n      throws IOException {\n    if (includeDirs != null) {\n      StringWriter out = new StringWriter();\n      PCPP pcpp = new PCPP(includeDirs, out);\n      BufferedReader reader =\n          new BufferedReader(new InputStreamReader(fo.openInputStream(), StandardCharsets.UTF_8));\n      pcpp.run(reader, fo.getName());\n      return new StringInputBuffer(fo.getName(), out.toString());\n    } else {\n      return fo;\n    }\n  }\n\n  static JavaFileObject makeStringSource(String name, String code, List<String> includeDirs) {\n    if (includeDirs != null) {\n      StringWriter out = new StringWriter();\n      PCPP pcpp = new PCPP(includeDirs, out);\n      try {\n        pcpp.run(new StringReader(code), name);\n      } catch (IOException exp) {\n        throw new RuntimeException(exp);\n      }\n      return new StringInputBuffer(name, out.toString());\n    } else {\n      return new StringInputBuffer(name, code);\n    }\n  }\n\n  static URI toURI(String name) {\n    File file = new File(name);\n    if (file.exists()) {\n      return file.toURI();\n    } else {\n      try {\n        return URI.create(\"mfm:///\" + name);\n      } catch (Exception exp) {\n        return URI.create(\"mfm:///org/openjdk/btrace/script/java/java_source\");\n      }\n    }\n  }\n\n  public Map<String, byte[]> getClassBytes() {\n    return classBytes;\n  }\n\n  @Override\n  public void close() throws IOException {\n    classBytes = new HashMap<>();\n  }\n\n  @Override\n  public void flush() throws IOException {}\n\n  @Override\n  public JavaFileObject getJavaFileForOutput(\n      JavaFileManager.Location location, String className, Kind kind, FileObject sibling)\n      throws IOException {\n    if (kind == Kind.CLASS) {\n      return new ClassOutputBuffer(className);\n    } else {\n      return super.getJavaFileForOutput(location, className, kind, sibling);\n    }\n  }\n\n  @Override\n  public JavaFileObject getJavaFileForInput(\n      JavaFileManager.Location location, String className, Kind kind) throws IOException {\n    JavaFileObject result = super.getJavaFileForInput(location, className, kind);\n    if (kind == Kind.SOURCE) {\n      return preprocessedFileObject(result, includeDirs);\n    } else {\n      return result;\n    }\n  }\n\n  /** A file object used to represent Java source coming from a string. */\n  private static class StringInputBuffer extends SimpleJavaFileObject {\n\n    final String code;\n\n    StringInputBuffer(String name, String code) {\n      super(toURI(name), Kind.SOURCE);\n      this.code = code;\n    }\n\n    @Override\n    public CharBuffer getCharContent(boolean ignoreEncodingErrors) {\n      return CharBuffer.wrap(code);\n    }\n\n    public Reader openReader() {\n      return new StringReader(code);\n    }\n  }\n\n  /** A file object that stores Java bytecode into the classBytes map. */\n  private class ClassOutputBuffer extends SimpleJavaFileObject {\n\n    private final String name;\n\n    ClassOutputBuffer(String name) {\n      super(toURI(name), Kind.CLASS);\n      this.name = name;\n    }\n\n    @Override\n    public OutputStream openOutputStream() {\n      return new FilterOutputStream(new ByteArrayOutputStream()) {\n\n        @Override\n        public void close() throws IOException {\n          out.close();\n          ByteArrayOutputStream bos = (ByteArrayOutputStream) out;\n          classBytes.put(name, bos.toByteArray());\n        }\n      };\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/PCPP.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.compiler;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport java.io.StreamTokenizer;\nimport java.io.Writer;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A minimal pseudo-C-preprocessor derived from PCPP of the GlueGen project.\n *\n * @author Kenneth B. Russell (original author)\n * @author A. Sundararajan (changes documented below)\n *     <p>Changes:\n *     <p>* Changed the package name. * Formatted with NetBeans. * Removed preservation of #define\n *     directives. commented #defines emission. * Commented out printing of line directives. * Print\n *     space char in output only for word tokens. This way multicharacter operators such as ==, !=\n *     etc. are property printed.\n */\npublic class PCPP {\n  private static final Logger log = LoggerFactory.getLogger(PCPP.class);\n\n  private static final boolean disableDebugPrint = true;\n  private final Printer printer;\n  /**\n   * Map containing the results of #define statements. We must evaluate certain very simple\n   * definitions. Macros and multi-f defines (which typically contain either macro definitions or\n   * expressions) are currently not handled.\n   */\n  private final Map<String, String> defineMap = new HashMap<>();\n\n  private final Set<String> nonConstantDefines = new HashSet<>();\n  /** List containing the #include paths as Strings */\n  private final List<String> includePaths;\n\n  private ParseState state;\n\n  public PCPP(List<String> includePaths) {\n    this.includePaths = includePaths;\n    printer = new Printer();\n  }\n\n  public PCPP(List<String> includePaths, Writer out) {\n    this.includePaths = includePaths;\n    printer = new Printer(out);\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  public static void main(String[] args) {\n    try {\n      Reader reader = null;\n      String filename = null;\n\n      if (args.length == 0) {\n        usage();\n      }\n\n      List<String> includePaths = new ArrayList<>();\n      for (int i = 0; i < args.length; i++) {\n        if (i < args.length - 1) {\n          String arg = args[i];\n          if (arg.startsWith(\"-I\")) {\n            String[] paths = arg.substring(2).split(System.getProperty(\"path.separator\"));\n            includePaths.addAll(Arrays.asList(paths));\n          } else {\n            usage();\n          }\n        } else {\n          String arg = args[i];\n          if (arg.equals(\"-\")) {\n            reader = new InputStreamReader(System.in);\n            filename = \"standard input\";\n          } else {\n            if (arg.startsWith(\"-\")) {\n              usage();\n            }\n            filename = arg;\n            reader = new BufferedReader(new FileReader(filename));\n          }\n        }\n      }\n\n      new PCPP(includePaths).run(reader, filename);\n    } catch (IOException e) {\n      log.error(\"Preprocessor failed\", e);\n      System.err.println(\"ERROR: Preprocessor failed: \" + e.getMessage());\n    }\n  }\n\n  // ----------------------------------------------------------------------\n  // Internals only below this point\n  //\n  private static void usage() {\n    System.out.println(\"Usage: java PCPP [filename | -]\");\n    System.out.println(\"Minimal pseudo-C-preprocessor.\");\n    System.out.println(\"Output goes to standard output. Standard input can be used as input\");\n    System.out.println(\"by passing '-' as the argument.\");\n    System.exit(1);\n  }\n\n  public void run(Reader reader, String filename) throws IOException {\n    StreamTokenizer tok = null;\n    BufferedReader bufReader = null;\n    if (reader instanceof BufferedReader) {\n      bufReader = (BufferedReader) reader;\n    } else {\n      bufReader = new BufferedReader(reader);\n    }\n    tok = new StreamTokenizer(new ConcatenatingReader(bufReader));\n    tok.resetSyntax();\n    tok.wordChars('a', 'z');\n    tok.wordChars('A', 'Z');\n    tok.wordChars('0', '9');\n    tok.wordChars('_', '_');\n    tok.wordChars('.', '.');\n    tok.wordChars(128 + 32, 255);\n    tok.whitespaceChars(0, ' ');\n    tok.quoteChar('\"');\n    tok.quoteChar('\\'');\n    tok.eolIsSignificant(true);\n    tok.slashSlashComments(true);\n    tok.slashStarComments(true);\n    ParseState curState = new ParseState(tok, filename);\n    ParseState oldState = state;\n    state = curState;\n    lineDirective();\n    parse();\n    state = oldState;\n    if (state != null) {\n      lineDirective();\n    }\n  }\n\n  public String findFile(String filename) {\n    String sep = File.separator;\n    for (String inclPath : includePaths) {\n      String fullPath = inclPath + sep + filename;\n      File file = new File(fullPath);\n      if (file.exists()) {\n        return fullPath;\n      }\n    }\n    return null;\n  }\n\n  // Accessors\n  private void pushBackToken() {\n    state.tok().pushBack();\n  }\n\n  /** Equivalent to nextToken(false) */\n  private int nextToken() throws IOException {\n    return nextToken(false);\n  }\n\n  private int nextToken(boolean returnEOLs) throws IOException {\n    int lineno = lineNumber();\n    // Check to see whether the previous call to nextToken() left an\n    // EOL on the stream\n    if (curToken() == StreamTokenizer.TT_EOL) {\n      state.setStartOfLine(true);\n    } else if (!state.startOfFile()) {\n      state.setStartOfLine(false);\n    }\n    state.setStartOfFile(false);\n    int val = state.tok().nextToken();\n    if (!returnEOLs) {\n      if (val == StreamTokenizer.TT_EOL) {\n        do {\n          // Consume and return next token, setting state appropriately\n          val = state.tok().nextToken();\n          state.setStartOfLine(true);\n          printer.println();\n        } while (val == StreamTokenizer.TT_EOL);\n      }\n    }\n    if (lineNumber() > lineno + 1) {\n      // This is a little noisier than it needs to be, but does handle\n      // the case of multi-line comments properly\n      lineDirective();\n    }\n    return val;\n  }\n\n  /** Reads the next token and throws an IOException if it is not the specified token character. */\n  private void nextRequiredToken(int requiredToken) throws IOException {\n    int nextTok = nextToken();\n    if (nextTok != requiredToken) {\n      String msg = \"Expected token '\" + requiredToken + \"' but got \";\n      switch (nextTok) {\n        case StreamTokenizer.TT_EOF:\n          msg += \"<EOF>\";\n          break;\n        case StreamTokenizer.TT_EOL:\n          msg += \"<EOL>\";\n          break;\n        default:\n          msg += \"'\" + curTokenAsString() + \"'\";\n          break;\n      }\n      msg += \" at file \" + filename() + \", line \" + lineNumber();\n      throw new IOException(msg);\n    }\n  }\n\n  private int curToken() {\n    return state.tok().ttype;\n  }\n\n  private String curTokenAsString() {\n    int t = curToken();\n    if (t == StreamTokenizer.TT_WORD) {\n      return curWord();\n    }\n    if (t == StreamTokenizer.TT_EOL) {\n      throw new RuntimeException(\"Should not be converting EOL characters to strings\");\n    }\n    char c = (char) t;\n    if (c == '\"' || c == '\\'') {\n      return c + state.tok().sval + c;\n    }\n    return String.valueOf(c);\n  }\n\n  private String nextWord() throws IOException {\n    int val = nextToken();\n    if (val != StreamTokenizer.TT_WORD) {\n      throw new RuntimeException(\"Expected word at file \" + filename() + \", line \" + lineNumber());\n    }\n    return curWord();\n  }\n\n  private String curWord() {\n    return state.tok().sval;\n  }\n\n  private boolean startOfLine() {\n    return state.startOfLine();\n  }\n\n  private String filename() {\n    return state.filename();\n  }\n\n  private int lineNumber() {\n    return state.lineNumber();\n  }\n\n  /////////////\n  // Parsing //\n  /////////////\n  private void parse() throws IOException {\n    int tok = 0;\n    while ((tok = nextToken()) != StreamTokenizer.TT_EOF) {\n      // A '#' at the beginning of a line is a preprocessor directive\n      if (startOfLine() && (tok == '#')) {\n        preprocessorDirective();\n      } else {\n        // Output white space plus current token, handling #defines\n        // (though not properly -- only handling #defines to constants and the empty string)\n\n        // !!HACK!! - print space only for word tokens. This way multicharacter\n        // operators such as ==, != etc. are property printed.\n        if (tok == StreamTokenizer.TT_WORD) {\n          printer.print(\" \");\n        }\n        String s = curTokenAsString();\n        String newS = defineMap.get(s);\n        if (newS == null) {\n          newS = s;\n        }\n        printer.print(newS);\n      }\n    }\n    printer.flush();\n  }\n\n  private void preprocessorDirective() throws IOException {\n    String w = nextWord();\n    boolean shouldPrint = true;\n    switch (w) {\n      case \"define\":\n        handleDefine();\n        shouldPrint = false;\n        break;\n      case \"undef\":\n        handleUndefine();\n        shouldPrint = false;\n        break;\n      case \"if\":\n      case \"elif\":\n        handleIf(w.equals(\"if\"));\n        shouldPrint = false;\n        break;\n      case \"ifdef\":\n      case \"ifndef\":\n        handleIfdef(w.equals(\"ifdef\"));\n        shouldPrint = false;\n        break;\n      case \"else\":\n        handleElse();\n        shouldPrint = false;\n        break;\n      case \"endif\":\n        handleEndif();\n        shouldPrint = false;\n        break;\n      case \"include\":\n        handleInclude();\n        shouldPrint = false;\n        break;\n        // Unknown preprocessor directive (#pragma?) -- ignore\n      default:\n        break;\n    }\n    if (shouldPrint) {\n      printer.print(\"# \");\n      printToken();\n    }\n  }\n\n  ////////////////////////////////////\n  // Handling of #define directives //\n  ////////////////////////////////////\n  private void handleUndefine() throws IOException {\n    // Next token is the name of the #undef\n    String name = nextWord();\n\n    debugPrint(true, \"#undef \" + name);\n\n    // there shouldn't be any extra symbols after the name, but just in case...\n    List<String> values = new ArrayList<>();\n    while (nextToken(true) != StreamTokenizer.TT_EOL) {\n      values.add(curTokenAsString());\n    }\n\n    if (printer.enabled()) {\n      String oldDef = defineMap.remove(name);\n      if (oldDef == null) {\n        System.err.println(\n            \"WARNING: ignoring redundant \\\"#undef \"\n                + name\n                + \"\\\", at \\\"\"\n                + filename()\n                + \"\\\" line \"\n                + lineNumber()\n                + \": \\\"\"\n                + name\n                + \"\\\" was not previously defined\");\n      } else {\n        // System.err.println(\"UNDEFINED: '\" + name + \"'  (line \" + lineNumber() + \" file \" +\n        // filename() + \")\");\n      }\n      nonConstantDefines.remove(name);\n    } else {\n      System.err.println(\n          \"FAILED TO UNDEFINE: '\"\n              + name\n              + \"'  (line \"\n              + lineNumber()\n              + \" file \"\n              + filename()\n              + \")\");\n    }\n  }\n\n  private void handleDefine() throws IOException {\n    // Next token is the name of the #define\n    String name = nextWord();\n    // System.err.println(\"IN HANDLE_DEFINE: '\" + name + \"'  (line \" + lineNumber() + \" file \" +\n    // filename() + \")\");\n    // (Note that this is not actually proper handling for multi-line #defines)\n    List<String> values = new ArrayList<>();\n    while (nextToken(true) != StreamTokenizer.TT_EOL) {\n      values.add(curTokenAsString());\n    }\n    // if we're not within an active block of code (like inside an \"#ifdef\n    // FOO\" where FOO isn't defined), then don't actually alter the definition\n    // map.\n    debugPrint(true, \"#define \" + name);\n    if (printer.enabled()) {\n      boolean emitDefine = true;\n\n      // Handle #definitions to nothing or to a constant value\n      int sz = values.size();\n      if (sz == 0) {\n        // definition to nothing, like \"#define FOO\"\n        String oldDef = defineMap.put(name, \"\");\n        if (oldDef != null) {\n          System.err.println(\"WARNING: \\\"\" + name + \"\\\" redefined from \\\"\" + oldDef + \"\\\" to \\\"\\\"\");\n        }\n        // We don't want to emit the define, because it would serve no purpose\n        // and cause GlueGen errors (confuse the GnuCParser)\n        emitDefine = false;\n        // System.out.println(\"//---DEFINED: \" + name + \"to \\\"\\\"\");\n      } else if (sz == 1) {\n        // See whether the value is a constant\n        String value = values.get(0);\n        if (isConstant(value)) {\n          // Value is numeric constant like \"#define FOO 5\".\n          // Put it in the #define map\n          String oldDef = defineMap.put(name, value);\n          if (oldDef != null) {\n            System.err.println(\n                \"WARNING: \\\"\" + name + \"\\\" redefined from \\\"\" + oldDef + \"\\\" to \\\"\" + value + \"\\\"\");\n          }\n          // System.out.println(\"//---DEFINED: \" + name + \" to \\\"\" + value + \"\\\"\");\n        } else {\n          // Value is a symbolic constant like \"#define FOO BAR\".\n          // Try to look up the symbol's value\n          String newValue = resolveDefine(value, true);\n          if (newValue != null) {\n            // Set the value to the value of the symbol.\n            //\n            // TO DO: Is this correct? Why not output the symbol unchanged?\n            // I think that it's a good thing to see that some symbols are\n            // defined in terms of others. -chris\n            values.set(0, newValue);\n          } else {\n            // Still perform textual replacement\n            defineMap.put(name, value);\n            nonConstantDefines.add(name);\n            emitDefine = false;\n          }\n        }\n      } else {\n        // Non-constant define; try to do reasonable textual substitution anyway\n        // (FIXME: should identify some of these, like (-1), as constants)\n        emitDefine = false;\n        StringBuilder val = new StringBuilder();\n        for (int i = 0; i < sz; i++) {\n          if (i != 0) {\n            val.append(\" \");\n          }\n          val.append(resolveDefine(values.get(i), false));\n        }\n        if (defineMap.get(name) != null) {\n          // This is probably something the user should investigate.\n          throw new RuntimeException(\n              \"Cannot redefine symbol \\\"\"\n                  + name\n                  + \" from \\\"\"\n                  + defineMap.get(name)\n                  + \"\\\" to non-constant \"\n                  + \" definition \\\"\"\n                  + val\n                  + \"\\\"\");\n        }\n        defineMap.put(name, val.toString());\n        nonConstantDefines.add(name);\n      }\n\n      if (emitDefine) {\n        // commenting out the #define in output\n        printer.print(\"// \");\n        // Print name and value\n        printer.print(\"# define \");\n        printer.print(name);\n        for (String line : values) {\n          printer.print(\" \");\n          printer.print(line);\n        }\n        printer.println();\n      }\n    } // end if (enabled())\n\n    // System.err.println(\"OUT HANDLE_DEFINE: \" + name);\n  }\n\n  private boolean isConstant(String s) {\n    if (s.startsWith(\"0x\") || s.startsWith(\"0X\")) {\n      return checkHex(s);\n    } else {\n      return checkDecimal(s);\n    }\n  }\n\n  private boolean checkHex(String s) {\n    for (int i = 2; i < s.length(); i++) {\n      char c = s.charAt(i);\n      if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  private boolean checkDecimal(String s) {\n    try {\n      Float.valueOf(s);\n    } catch (NumberFormatException e) {\n      // not parsable as a number\n      return false;\n    }\n    return true;\n  }\n\n  private String resolveDefine(String word, boolean returnNullIfNotFound) {\n    String lastWord = defineMap.get(word);\n    if (lastWord == null) {\n      if (returnNullIfNotFound) {\n        return null;\n      }\n      return word;\n    }\n    String nextWord = null;\n    do {\n      nextWord = defineMap.get(lastWord);\n      if (nextWord != null) {\n        lastWord = nextWord;\n      }\n    } while (nextWord != null);\n    return lastWord;\n  }\n\n  /**\n   * @param isIfdef if true, we're processing #ifdef; if false, we're processing #ifndef.\n   */\n  private void handleIfdef(boolean isIfdef) throws IOException {\n    // Next token is the name of the #ifdef\n    String symbolName = nextWord();\n    debugPrint(true, (isIfdef ? \"#ifdef \" : \"#ifndef \") + symbolName);\n    boolean symbolIsDefined = defineMap.get(symbolName) != null;\n    // debugPrint(true, \"HANDLE_IFDEF: ifdef(\" + symbolName + \") = \" + symbolIsDefined );\n    printer.pushEnableBit(printer.enabled() && symbolIsDefined == isIfdef);\n  }\n\n  ////////////////////////////////////////////////\n  // Handling of #if/#ifdef/ifndef/endif directives //\n  ////////////////////////////////////////////////\n\n  /** Handles #else directives */\n  private void handleElse() {\n    boolean enabledStatusBeforeElse = printer.enabled();\n    printer.popEnableBit();\n    printer.pushEnableBit(printer.enabled() && !enabledStatusBeforeElse);\n    debugPrint(true, \"#else \");\n  }\n\n  private void handleEndif() {\n    boolean enabledBeforePopping = printer.enabled();\n    printer.popEnableBit();\n\n    // print the endif if we were enabled prior to popEnableBit() (sending\n    // false to debugPrint means \"print regardless of current enabled() state).\n    debugPrint(!enabledBeforePopping, \"#endif/end-else\");\n  }\n\n  /**\n   * @param isIf if true, we're processing #if; if false, we're processing #elif.\n   */\n  private void handleIf(boolean isIf) throws IOException {\n    // System.out.println(\"IN HANDLE_\" + (isIf ? \"IF\" : \"ELIF\") + \" file \\\"\" + filename() + \" line \"\n    // + lineNumber());\n    debugPrint(true, (isIf ? \"#if\" : \"#elif\"));\n    boolean defineEvaluatedToTrue = handleIfRecursive(true);\n    if (!isIf) {\n      printer.popEnableBit();\n    }\n    printer.pushEnableBit(printer.enabled() && defineEvaluatedToTrue == isIf);\n    // System.out.println(\"OUT HANDLE_\" + (isIf ? \"IF\" : \"ELIF\") +\" (evaluated to \" +\n    // defineEvaluatedToTrue + \")\");\n  }\n\n  /**\n   * This method is called recursively to process nested sub-expressions such as:\n   *\n   * <pre>\n   *   #if !defined(OPENSTEP) && !(defined(NeXT) || !defined(NeXT_PDO))\n   * </pre>\n   *\n   * @param greedy if true, continue evaluating sub-expressions until EOL is reached. If false,\n   *     return as soon as the first sub-expression is processed.\n   * @return the value of the sub-expression or (if greedy==true) series of sub-expressions.\n   */\n  private boolean handleIfRecursive(boolean greedy) throws IOException {\n    // System.out.println(\"IN HANDLE_IF_RECURSIVE (\" + ++tmp + \", greedy = \" + greedy + \")\");\n    // System.out.flush();\n\n    // ifValue keeps track of the current value of the potentially nested\n    // \"defined()\" expressions as we process them.\n    boolean ifValue = true;\n    int openParens = 0;\n    int tok;\n    do {\n      tok = nextToken(true);\n      // System.out.println(\"-- READ: [\" + (tok == StreamTokenizer.TT_EOL ? \"<EOL>\"\n      // :curTokenAsString()) + \"]\");\n      switch (tok) {\n        case '(':\n          ++openParens;\n          // System.out.println(\"OPEN PARENS = \" + openParens);\n          ifValue = ifValue && handleIfRecursive(true);\n          break;\n        case ')':\n          --openParens;\n          // System.out.println(\"OPEN PARENS = \" + openParens);\n          break;\n        case '!':\n          {\n            // System.out.println(\"HANDLE_IF_RECURSIVE HANDLING !\");\n            boolean rhs = handleIfRecursive(false);\n            ifValue = !rhs;\n            // System.out.println(\"HANDLE_IF_RECURSIVE HANDLED OUT !, RHS = \" + rhs);\n          }\n          break;\n        case '&':\n          {\n            nextRequiredToken('&');\n            // System.out.println(\"HANDLE_IF_RECURSIVE HANDLING &&, LHS = \" + ifValue);\n            boolean rhs = handleIfRecursive(true);\n            // System.out.println(\"HANDLE_IF_RECURSIVE HANDLED &&, RHS = \" + rhs);\n            ifValue = ifValue && rhs;\n          }\n          break;\n        case '|':\n          {\n            nextRequiredToken('|');\n            // System.out.println(\"HANDLE_IF_RECURSIVE HANDLING ||, LHS = \" + ifValue);\n            boolean rhs = handleIfRecursive(true);\n            // System.out.println(\"HANDLE_IF_RECURSIVE HANDLED ||, RHS = \" + rhs);\n            ifValue = ifValue || rhs;\n          }\n          break;\n        case '>':\n        case '<':\n        case '=':\n          {\n            // NOTE: we don't handle expressions like this properly\n            boolean rhs = handleIfRecursive(true);\n            ifValue = false;\n          }\n          break;\n        case StreamTokenizer.TT_WORD:\n          {\n            String word = curTokenAsString();\n            if (word.equals(\"defined\")) {\n              // Handle things like #if defined(SOMESYMBOL)\n              nextRequiredToken('(');\n              String symbol = nextWord();\n              boolean isDefined = defineMap.get(symbol) != null;\n              // System.out.println(\"HANDLE_IF_RECURSIVE HANDLING defined(\" + symbol + \") = \" +\n              // isDefined);\n              ifValue = ifValue && isDefined;\n              nextRequiredToken(')');\n            } else {\n              // Handle things like #if SOME_SYMBOL.\n              String symbolValue = defineMap.get(word);\n\n              // See if the statement is \"true\"; i.e., a non-zero expression\n              if (symbolValue != null) {\n                // The statement is true if the symbol is defined and is a constant expression\n                return (!nonConstantDefines.contains(word));\n              } else {\n                // The statement is true if the symbol evaluates to a non-zero value\n                //\n                // NOTE: This doesn't yet handle evaluable expressions like \"#if\n                // SOME_SYMBOL > 5\" or \"#if SOME_SYMBOL == 0\", both of which are\n                // valid syntax. It only handles numeric symbols like \"#if 1\"\n\n                try {\n                  // see if it's in decimal form\n                  return Double.parseDouble(word) != 0;\n                } catch (NumberFormatException nfe1) {\n                  try {\n                    // ok, it's not a valid decimal value, try hex/octal value\n                    return Long.parseLong(word) != 0;\n                  } catch (NumberFormatException nfe2) {\n                    try {\n                      // ok, it's not a valid hex/octal value, try boolean\n                      return Boolean.parseBoolean(word);\n                    } catch (NumberFormatException nfe3) {\n                      // give up; the symbol isn't a numeric or boolean value\n                      return false;\n                    }\n                  }\n                }\n              }\n            }\n          } // end case TT_WORD\n          break;\n        case StreamTokenizer.TT_EOL:\n          // System.out.println(\"HANDLE_IF_RECURSIVE HIT <EOL>!\");\n          pushBackToken(); // so caller hits EOL as well if we're recursing\n          break;\n        case StreamTokenizer.TT_EOF:\n          throw new RuntimeException(\n              \"Unexpected end of file while parsing \"\n                  + \"#if statement at file \"\n                  + filename()\n                  + \", line \"\n                  + lineNumber());\n\n        default:\n          throw new RuntimeException(\n              \"Unexpected token (\"\n                  + curTokenAsString()\n                  + \") while parsing \"\n                  + \"#if statement at file \"\n                  + filename()\n                  + \", line \"\n                  + lineNumber());\n      }\n      // System.out.println(\"END OF WHILE: greedy = \" + greedy + \" parens = \" +openParens + \" not\n      // EOL = \" + (tok != StreamTokenizer.TT_EOL) + \" --> \" + ((greedy && openParens >= 0) && tok\n      // != StreamTokenizer.TT_EOL));\n    } while ((greedy && openParens >= 0) && tok != StreamTokenizer.TT_EOL);\n    // System.out.println(\"OUT HANDLE_IF_RECURSIVE (\" + tmp-- + \", returning \" + ifValue + \")\");\n    // System.out.flush();\n    return ifValue;\n  }\n\n  // static int tmp = -1;\n\n  /////////////////////////////////////\n  // Handling of #include directives //\n  /////////////////////////////////////\n  @SuppressWarnings(\"DefaultCharset\")\n  private void handleInclude() throws IOException {\n    // Two kinds of #includes: one with quoted string for argument,\n    // one with angle brackets surrounding argument\n    int t = nextToken();\n    String filename = null;\n    if (t == '\"') {\n      filename = curWord();\n    } else if (t == '<') {\n      // Components of path name are coming in as separate tokens;\n      // concatenate them\n      StringBuilder buf = new StringBuilder();\n      while ((t = nextToken()) != '>' && (t != StreamTokenizer.TT_EOF)) {\n        buf.append(curTokenAsString());\n      }\n      if (t == StreamTokenizer.TT_EOF) {\n        System.err.println(\"WARNING: unexpected EOF while processing #include directive\");\n      }\n      filename = buf.toString();\n    }\n    // if we're not within an active block of code (like inside an \"#ifdef\n    // FOO\" where FOO isn't defined), then don't actually process the\n    // #included file.\n    debugPrint(true, \"#include [\" + filename + \"]\");\n    if (printer.enabled()) {\n      // Look up file in known #include path\n      String fullname = findFile(filename);\n      // System.out.println(\"ACTIVE BLOCK, LOADING \" + filename);\n      if (fullname == null) {\n        System.err.println(\"WARNING: unable to find #include file \\\"\" + filename + \"\\\"\");\n        return;\n      }\n      // Process this file in-line\n      Reader reader = new BufferedReader(new FileReader(fullname));\n      run(reader, fullname);\n    } else {\n      // System.out.println(\"INACTIVE BLOCK, SKIPPING \" + filename);\n    }\n  }\n\n  private void debugPrint(boolean onlyPrintIfEnabled, String msg) {\n    if (disableDebugPrint) {\n      return;\n    }\n\n    if (!onlyPrintIfEnabled || printer.enabled()) {\n      for (int i = Printer.debugPrintIndentLevel; --i > 0; ) {\n        System.out.print(\"  \");\n      }\n      System.out.println(msg + \"  (line \" + lineNumber() + \" file \" + filename() + \")\");\n    }\n  }\n\n  private void printToken() {\n    printer.print(curTokenAsString());\n  }\n\n  private void lineDirective() {\n    /*\n     * Originally this code was emitting line directives. We don't need those.\n     *\n     * print(\"# \" + lineNumber() + \" \\\"\" + filename() + \"\\\"\");\n     * println();\n     */\n  }\n\n  // State\n  static class ParseState {\n\n    private final StreamTokenizer tok;\n    private final String filename;\n    // We do not generate #line directives\n    // private int lineNumber;\n    private boolean startOfLine;\n    private boolean startOfFile;\n\n    ParseState(StreamTokenizer tok, String filename) {\n      this.tok = tok;\n      this.filename = filename;\n      // We do not generate #line directives\n      // lineNumber = 1;\n      startOfLine = true;\n      startOfFile = true;\n    }\n\n    StreamTokenizer tok() {\n      return tok;\n    }\n\n    String filename() {\n      return filename;\n    }\n\n    int lineNumber() {\n      return tok.lineno();\n    }\n\n    boolean startOfLine() {\n      return startOfLine;\n    }\n\n    void setStartOfLine(boolean val) {\n      startOfLine = val;\n    }\n\n    boolean startOfFile() {\n      return startOfFile;\n    }\n\n    void setStartOfFile(boolean val) {\n      startOfFile = val;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/PackGenerator.java",
    "content": "package org.openjdk.btrace.compiler;\n\nimport java.io.IOException;\n\npublic interface PackGenerator {\n  byte[] generateProbePack(byte[] data) throws IOException;\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/Postprocessor.java",
    "content": "/*\n * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.compiler;\n\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Deque;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport org.objectweb.asm.AnnotationVisitor;\nimport org.objectweb.asm.Attribute;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.FieldVisitor;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic class Postprocessor extends ClassVisitor {\n  private final List<FieldDescriptor> fields = new ArrayList<>();\n  private boolean shortSyntax = false;\n  private String className = \"\";\n\n  public Postprocessor(ClassVisitor cv) {\n    super(Opcodes.ASM9, cv);\n  }\n\n  @Override\n  public void visit(\n      int version,\n      int access,\n      String name,\n      String signature,\n      String superName,\n      String[] interfaces) {\n    if (((access & Opcodes.ACC_PUBLIC)\n            | (access & Opcodes.ACC_PROTECTED)\n            | (access & Opcodes.ACC_PRIVATE))\n        == 0) {\n      shortSyntax =\n          true; // specifying \"class <MyClass>\" rather than \"public class <MyClass>\" means using\n      // short syntax\n      access |= Opcodes.ACC_PUBLIC; // force the public modifier on the btrace class\n    }\n    className = name;\n    super.visit(version, access, name, signature, superName, interfaces);\n  }\n\n  @Override\n  public MethodVisitor visitMethod(\n      int access, String name, String desc, String signature, String[] exceptions) {\n    if (!shortSyntax) return super.visitMethod(access, name, desc, signature, exceptions);\n\n    if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE)) == 0) {\n      access &= ~Opcodes.ACC_PROTECTED;\n      access |= Opcodes.ACC_PUBLIC;\n    }\n    int localVarOffset = ((access & Opcodes.ACC_STATIC) == 0) ? -1 : 0;\n    access |= Opcodes.ACC_STATIC;\n\n    boolean isconstructor = false;\n    if (\"<init>\".equals(name)) {\n      name = \"<clinit>\";\n      isconstructor = true;\n    }\n\n    if (isconstructor) {\n      // the script class needs as dummy default constructor\n      createDefaultConstructor();\n    }\n\n    return new MethodConvertor(\n        localVarOffset,\n        isconstructor,\n        super.visitMethod(access, name, desc, signature, exceptions));\n  }\n\n  private void createDefaultConstructor() {\n    MethodVisitor mv = super.visitMethod(Opcodes.ACC_PUBLIC, \"<init>\", \"()V\", null, null);\n    mv.visitCode();\n    // load 'this'\n    mv.visitVarInsn(Opcodes.ALOAD, 0);\n    // invoke super constructor\n    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, \"java/lang/Object\", \"<init>\", \"()V\", false);\n    mv.visitMaxs(1, 1);\n    mv.visitEnd();\n  }\n\n  @Override\n  public FieldVisitor visitField(\n      int access, String name, String desc, String signature, Object value) {\n    if (!shortSyntax) return super.visitField(access, name, desc, signature, value);\n\n    List<Attribute> attrs = new ArrayList<>();\n    return new FieldVisitor(Opcodes.ASM9) {\n      private final List<AnnotationDef> annotations = new ArrayList<>();\n\n      @Override\n      public AnnotationVisitor visitAnnotation(String type, boolean visible) {\n        AnnotationDef ad = new AnnotationDef(type);\n        annotations.add(ad);\n        return new AnnotationVisitor(Opcodes.ASM9, super.visitAnnotation(type, visible)) {\n          @Override\n          public void visit(String name, Object val) {\n            ad.addValue(name, val);\n            super.visit(name, val);\n          }\n        };\n      }\n\n      @Override\n      public void visitAttribute(Attribute atrbt) {\n        super.visitAttribute(atrbt);\n        attrs.add(atrbt);\n      }\n\n      @Override\n      public void visitEnd() {\n        FieldDescriptor fd =\n            new FieldDescriptor(access, name, desc, signature, value, attrs, annotations);\n        fields.add(fd);\n        super.visitEnd();\n      }\n    };\n  }\n\n  @Override\n  public void visitEnd() {\n    if (shortSyntax) {\n      addFields();\n    }\n  }\n\n  private void addFields() {\n    for (FieldDescriptor fd : fields) {\n      String fieldName = fd.name;\n      int fieldAccess = fd.access;\n      String fieldDesc = fd.desc;\n      String fieldSignature = fd.signature;\n      Object fieldValue = fd.value;\n\n      fieldAccess &= ~Opcodes.ACC_PRIVATE;\n      fieldAccess &= ~Opcodes.ACC_PROTECTED;\n      fieldAccess |= Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC;\n\n      FieldVisitor fv =\n          super.visitField(fieldAccess, fieldName, fieldDesc, fieldSignature, fieldValue);\n\n      for (AnnotationDef ad : fd.annotations) {\n        AnnotationVisitor av = fv.visitAnnotation(ad.getType(), true);\n        for (Map.Entry<String, Object> attr : ad.getValues().entrySet()) {\n          av.visit(attr.getKey(), attr.getValue());\n        }\n      }\n\n      for (Attribute attr : fd.attributes) {\n        fv.visitAttribute(attr);\n      }\n      fv.visitEnd();\n    }\n  }\n\n  private static final class AnnotationDef {\n    private final String type;\n    private final Map<String, Object> values = new HashMap<>();\n\n    public AnnotationDef(String type) {\n      this.type = type;\n    }\n\n    public void addValue(String name, Object val) {\n      values.put(name, val);\n    }\n\n    public String getType() {\n      return type;\n    }\n\n    public Map<String, Object> getValues() {\n      return values;\n    }\n  }\n\n  private static class FieldDescriptor {\n    final int access;\n    final String name, desc, signature;\n    final Object value;\n    final List<Attribute> attributes;\n    final List<AnnotationDef> annotations;\n    int var = -1;\n    boolean initialized;\n\n    FieldDescriptor(\n        int acc,\n        String n,\n        String d,\n        String sig,\n        Object val,\n        List<Attribute> attrs,\n        List<AnnotationDef> annots) {\n      access = acc;\n      name = n;\n      desc = d;\n      signature = sig;\n      value = val;\n      attributes = attrs;\n      annotations = annots;\n    }\n  }\n\n  private class MethodConvertor extends MethodVisitor {\n    private final Deque<Boolean> simulatedStack = new ArrayDeque<>();\n    private final boolean isConstructor;\n    private int localVarOffset = 0;\n    private boolean copyEnabled = false;\n\n    public MethodConvertor(int localVarOffset, boolean isConstructor, MethodVisitor mv) {\n      super(Opcodes.ASM9, mv);\n      this.localVarOffset = localVarOffset;\n      this.isConstructor = isConstructor;\n      copyEnabled = !isConstructor; // copy is enabled by default for all methods except constructor\n    }\n\n    @Override\n    public void visitLocalVariable(\n        String name, String desc, String signature, Label start, Label end, int index) {\n      if (index + localVarOffset < 0 || !copyEnabled) {\n        return;\n      }\n      super.visitLocalVariable(name, desc, signature, start, end, index + localVarOffset);\n    }\n\n    @Override\n    public void visitVarInsn(int opcode, int var) {\n      boolean delegate = true;\n      switch (opcode) {\n        case Opcodes.ALOAD:\n          {\n            delegate = (var + localVarOffset) >= 0;\n            simulatedStack.push(!delegate);\n            break;\n          }\n        case Opcodes.LLOAD:\n        case Opcodes.DLOAD:\n          {\n            simulatedStack.push(Boolean.FALSE);\n            // long and double occupy 2 stack slots; fall through\n          }\n        case Opcodes.ILOAD:\n        case Opcodes.FLOAD:\n          {\n            simulatedStack.push(Boolean.FALSE);\n            break;\n          }\n        case Opcodes.LSTORE:\n        case Opcodes.DSTORE:\n          {\n            simulatedStack.poll();\n            // long and double occupy 2 stack slots; fall through\n          }\n        case Opcodes.ASTORE:\n        case Opcodes.ISTORE:\n        case Opcodes.FSTORE:\n          {\n            simulatedStack.poll();\n            break;\n          }\n      }\n\n      if (delegate && copyEnabled) super.visitVarInsn(opcode, var + localVarOffset);\n    }\n\n    @Override\n    public void visitInsn(int opcode) {\n      switch (opcode) {\n        case Opcodes.POP:\n          {\n            if (simulatedStack.pop()) {\n              return;\n            }\n            break;\n          }\n        case Opcodes.POP2:\n          {\n            Boolean[] vals = new Boolean[2];\n            vals[0] = simulatedStack.poll();\n            vals[1] = simulatedStack.poll();\n            if (vals[0] && vals[1]) {\n              return;\n            } else if (vals[0] || vals[1]) {\n              opcode = Opcodes.POP;\n            }\n            break;\n          }\n        case Opcodes.DUP:\n          {\n            Boolean val = simulatedStack.peek();\n            val = val != null ? val : Boolean.FALSE;\n            simulatedStack.push(val);\n            if (val) return;\n            break;\n          }\n        case Opcodes.DUP_X1:\n          {\n            if (simulatedStack.size() < 2) return;\n            Boolean[] vals = new Boolean[2];\n            int cntr = vals.length - 1;\n            while (cntr >= 0) {\n              vals[cntr--] = simulatedStack.pop();\n            }\n            simulatedStack.push(vals[vals.length - 1]);\n            simulatedStack.addAll(Arrays.asList(vals));\n            if (vals[1]) {\n              return;\n            } else if (vals[0]) {\n              opcode = Opcodes.DUP;\n            }\n            break;\n          }\n        case Opcodes.DUP_X2:\n          {\n            if (simulatedStack.size() < 3) return;\n            Boolean[] vals = new Boolean[3];\n            int cntr = vals.length - 1;\n            while (cntr >= 0) {\n              vals[cntr--] = simulatedStack.pop();\n            }\n            simulatedStack.push(vals[vals.length - 1]);\n            simulatedStack.addAll(Arrays.asList(vals));\n            if (vals[2]) {\n              return;\n            } else if (vals[0] && vals[1]) {\n              opcode = Opcodes.DUP;\n            } else {\n              opcode = Opcodes.DUP_X1;\n            }\n            break;\n          }\n        case Opcodes.DUP2:\n          {\n            if (simulatedStack.size() < 2) return;\n            Boolean[] vals = new Boolean[2];\n            int cntr = vals.length - 1;\n            while (cntr >= 0) {\n              vals[cntr--] = simulatedStack.pop();\n            }\n            simulatedStack.addAll(Arrays.asList(vals));\n            if (vals[0] && vals[1]) {\n              return;\n            } else if (vals[0] || vals[1]) {\n              opcode = Opcodes.DUP;\n            }\n            break;\n          }\n        case Opcodes.DUP2_X1:\n          {\n            if (simulatedStack.size() < 3) return;\n            Boolean[] vals = new Boolean[3];\n            int cntr = vals.length - 1;\n            while (cntr >= 0) {\n              vals[cntr--] = simulatedStack.pop();\n            }\n            simulatedStack.push(vals[vals.length - 2]);\n            simulatedStack.push(vals[vals.length - 1]);\n            simulatedStack.addAll(Arrays.asList(vals));\n            if (vals[1] && vals[2]) {\n              return;\n            }\n            if (vals[0]) {\n              if (vals[1] || vals[2]) {\n                opcode = Opcodes.DUP;\n              } else {\n                opcode = Opcodes.DUP2;\n              }\n            } else {\n              if (vals[1] || vals[2]) {\n                opcode = Opcodes.DUP_X1;\n              }\n            }\n            break;\n          }\n        case Opcodes.DUP2_X2:\n          {\n            Boolean[] vals = {Boolean.FALSE, Boolean.FALSE, Boolean.FALSE, Boolean.FALSE};\n            Iterator<Boolean> iter = simulatedStack.descendingIterator();\n            int cntr = 0;\n            while (cntr < vals.length && iter.hasNext()) {\n              vals[cntr++] = iter.next();\n            }\n            simulatedStack.push(vals[vals.length - 2]);\n            simulatedStack.push(vals[vals.length - 1]);\n            simulatedStack.addAll(Arrays.asList(vals));\n            break;\n          }\n        case Opcodes.SWAP:\n          {\n            if (simulatedStack.size() < 2) return;\n            Boolean[] vals = new Boolean[2];\n\n            int cntr = vals.length - 1;\n            while (cntr >= 0) {\n              vals[cntr--] = simulatedStack.pop();\n            }\n            if (vals[0] || vals[1]) {\n              return;\n            }\n            simulatedStack.push(vals[1]);\n            simulatedStack.push(vals[0]);\n            break;\n          }\n          // zero operand instructions\n        case Opcodes.LCONST_0:\n        case Opcodes.LCONST_1:\n        case Opcodes.DCONST_0:\n        case Opcodes.DCONST_1:\n          {\n            simulatedStack.push(Boolean.FALSE);\n            // the value occupies 2 slots on stack\n            // fall through\n          }\n        case Opcodes.ICONST_0:\n        case Opcodes.ICONST_1:\n        case Opcodes.ICONST_2:\n        case Opcodes.ICONST_3:\n        case Opcodes.ICONST_4:\n        case Opcodes.ICONST_5:\n        case Opcodes.ICONST_M1:\n        case Opcodes.FCONST_0:\n        case Opcodes.FCONST_1:\n        case Opcodes.FCONST_2:\n        case Opcodes.ACONST_NULL:\n        case Opcodes.MONITORENTER:\n        case Opcodes.MONITOREXIT:\n          {\n            simulatedStack.push(Boolean.FALSE);\n            break;\n          }\n\n          // one operand instructions\n        case Opcodes.INEG:\n        case Opcodes.FNEG:\n        case Opcodes.DNEG:\n        case Opcodes.LNEG:\n        case Opcodes.I2B:\n        case Opcodes.I2C:\n        case Opcodes.I2F:\n        case Opcodes.I2S:\n        case Opcodes.L2D:\n        case Opcodes.D2L:\n        case Opcodes.F2I:\n        case Opcodes.CHECKCAST:\n        case Opcodes.ARRAYLENGTH:\n          {\n            // nothing changes in regard to the simulated stack\n            break;\n          }\n        case Opcodes.I2L:\n        case Opcodes.I2D:\n          {\n            simulatedStack.push(Boolean.FALSE); // extending the original value by one slot\n            break;\n          }\n\n          // two operand instructions\n        case Opcodes.LADD:\n        case Opcodes.DADD:\n        case Opcodes.LSUB:\n        case Opcodes.DSUB:\n        case Opcodes.LMUL:\n        case Opcodes.DMUL:\n        case Opcodes.LDIV:\n        case Opcodes.DDIV:\n        case Opcodes.LREM:\n        case Opcodes.DREM:\n        case Opcodes.LSHL:\n        case Opcodes.LSHR:\n        case Opcodes.LUSHR:\n        case Opcodes.LAND:\n        case Opcodes.LOR:\n        case Opcodes.LXOR:\n        case Opcodes.LALOAD:\n        case Opcodes.DALOAD:\n          {\n            simulatedStack.pop();\n            simulatedStack.pop();\n            // remove 4 slots == 2 long/double operands and add 2 slots == 1 long/double result\n            break;\n          }\n        case Opcodes.LCMP:\n        case Opcodes.DCMPL:\n        case Opcodes.DCMPG:\n          {\n            simulatedStack.pop();\n            simulatedStack.pop();\n            simulatedStack.pop();\n            // remove 4 slots == 2 long/double operands and add 1 slot == 1 int result\n            break;\n          }\n        case Opcodes.IADD:\n        case Opcodes.FADD:\n        case Opcodes.ISUB:\n        case Opcodes.FSUB:\n        case Opcodes.IMUL:\n        case Opcodes.IDIV:\n        case Opcodes.FDIV:\n        case Opcodes.IREM:\n        case Opcodes.FREM:\n        case Opcodes.ISHL:\n        case Opcodes.ISHR:\n        case Opcodes.IUSHR:\n        case Opcodes.IAND:\n        case Opcodes.IOR:\n        case Opcodes.IXOR:\n        case Opcodes.FCMPL:\n        case Opcodes.FCMPG:\n        case Opcodes.BALOAD:\n        case Opcodes.SALOAD:\n        case Opcodes.CALOAD:\n        case Opcodes.IALOAD:\n        case Opcodes.FALOAD:\n          {\n            simulatedStack.poll();\n            // remove 2 slots == 2 intoperands and add 1 slot == 1 int result\n            break;\n          }\n\n          // three operand instructions\n        case Opcodes.LASTORE:\n        case Opcodes.DASTORE:\n          {\n            simulatedStack.pop();\n            // LASTORE, DSTORE occupy one more slot compared to BASTORE etc.; falling through\n            // fall through\n          }\n        case Opcodes.BASTORE: // fall through\n        case Opcodes.CASTORE: // fall through\n        case Opcodes.SASTORE: // fall through\n        case Opcodes.IASTORE: // fall through\n        case Opcodes.FASTORE:\n          {\n            simulatedStack.pop();\n            simulatedStack.pop();\n            simulatedStack.pop();\n          }\n      }\n      if (copyEnabled) {\n        super.visitInsn(opcode);\n      }\n    }\n\n    @Override\n    public void visitIntInsn(int opcode, int index) {\n      switch (opcode) {\n        case Opcodes.BIPUSH:\n        case Opcodes.SIPUSH:\n          {\n            simulatedStack.push(Boolean.FALSE);\n            break;\n          }\n      }\n      if (copyEnabled) {\n        super.visitIntInsn(opcode, index);\n      }\n    }\n\n    @Override\n    public void visitJumpInsn(int opcode, Label label) {\n      switch (opcode) {\n        case Opcodes.IFEQ:\n        case Opcodes.IFNE:\n        case Opcodes.IFLE:\n        case Opcodes.IFGE:\n        case Opcodes.IFGT:\n        case Opcodes.IFLT:\n        case Opcodes.IFNULL:\n        case Opcodes.IFNONNULL:\n          {\n            simulatedStack.poll();\n            break;\n          }\n        case Opcodes.IF_ICMPEQ:\n        case Opcodes.IF_ICMPGE:\n        case Opcodes.IF_ICMPGT:\n        case Opcodes.IF_ICMPLE:\n        case Opcodes.IF_ICMPLT:\n        case Opcodes.IF_ICMPNE:\n          {\n            simulatedStack.poll();\n            simulatedStack.poll();\n            break;\n          }\n      }\n      if (copyEnabled) {\n        super.visitJumpInsn(opcode, label);\n      }\n    }\n\n    @Override\n    public void visitTableSwitchInsn(int i, int i1, Label label, Label... labels) {\n      simulatedStack.poll();\n      if (copyEnabled) {\n        super.visitTableSwitchInsn(i, i1, label, labels);\n      }\n    }\n\n    @Override\n    public void visitLookupSwitchInsn(Label label, int[] ints, Label[] labels) {\n      simulatedStack.poll();\n      if (copyEnabled) {\n        super.visitLookupSwitchInsn(label, ints, labels);\n      }\n    }\n\n    @Override\n    public void visitLdcInsn(Object o) {\n      simulatedStack.push(Boolean.FALSE);\n      if (o instanceof Long || o instanceof Double) {\n        simulatedStack.push(Boolean.FALSE);\n      }\n      if (copyEnabled) {\n        super.visitLdcInsn(o);\n      }\n    }\n\n    @Override\n    public void visitMaxs(int maxStack, int maxLocals) {\n      super.visitMaxs(maxStack, (Math.max(maxLocals + localVarOffset, 0)));\n    }\n\n    @Override\n    public void visitIincInsn(int var, int increment) {\n      if (copyEnabled) {\n        super.visitIincInsn(var + localVarOffset, increment);\n      }\n    }\n\n    @Override\n    public void visitFieldInsn(int i, String clazz, String name, String desc) {\n      if (i == Opcodes.GETFIELD) {\n        Boolean opTarget = simulatedStack.poll();\n        opTarget = opTarget != null ? opTarget : Boolean.FALSE;\n        if (opTarget) {\n          i = Opcodes.GETSTATIC;\n        }\n      } else if (i == Opcodes.PUTFIELD) {\n        simulatedStack.pop();\n        simulatedStack.pop();\n        if (desc.equals(\"J\") || desc.equals(\"D\")) {\n          simulatedStack.pop();\n        }\n        if (clazz.equals(className)) { // all local fields are static\n          i = Opcodes.PUTSTATIC;\n        }\n      }\n      switch (i) {\n        case Opcodes.GETFIELD:\n        case Opcodes.GETSTATIC:\n          {\n            simulatedStack.push(Boolean.FALSE);\n            if (desc.equals(\"J\") || desc.equals(\"D\")) {\n              simulatedStack.push(Boolean.FALSE);\n            }\n            break;\n          }\n      }\n      if (copyEnabled) {\n        super.visitFieldInsn(i, clazz, name, desc);\n      }\n    }\n\n    @Override\n    public void visitMethodInsn(\n        int opcode, String clazz, String method, String desc, boolean iface) {\n      int origOpcode = opcode;\n      Type[] args = Type.getArgumentTypes(desc);\n      for (Type t : args) {\n        for (int i = 0; i < t.getSize(); i++) {\n          simulatedStack.poll();\n        }\n      }\n      if (opcode != Opcodes.INVOKESTATIC) {\n        Boolean targetVal = simulatedStack.poll();\n        if (targetVal != null\n            && targetVal) { // \"true\" on stack means the original reference to \"this\"\n          opcode = Opcodes.INVOKESTATIC;\n        }\n      }\n      if (!Type.getReturnType(desc).equals(Type.VOID_TYPE)) {\n        simulatedStack.push(Boolean.FALSE);\n      }\n      if (!copyEnabled) {\n        if (origOpcode == Opcodes.INVOKESPECIAL && isConstructor) {\n          copyEnabled = true;\n        }\n      } else {\n        super.visitMethodInsn(opcode, clazz, method, desc, iface);\n      }\n    }\n\n    @Override\n    public AnnotationVisitor visitAnnotation(String string, boolean bln) {\n      return copyEnabled\n          ? super.visitAnnotation(string, bln)\n          : new AnnotationVisitor(Opcodes.ASM9) {};\n    }\n\n    @Override\n    public AnnotationVisitor visitAnnotationDefault() {\n      return copyEnabled ? super.visitAnnotationDefault() : new AnnotationVisitor(Opcodes.ASM9) {};\n    }\n\n    @Override\n    public void visitAttribute(Attribute atrbt) {\n      if (copyEnabled) {\n        super.visitAttribute(atrbt);\n      }\n    }\n\n    @Override\n    public void visitMultiANewArrayInsn(String string, int i) {\n      for (int ind = 0; ind < i; ind++) {\n        simulatedStack.pop();\n      }\n      simulatedStack.push(Boolean.FALSE);\n      if (copyEnabled) {\n        super.visitMultiANewArrayInsn(string, i);\n      }\n    }\n\n    @Override\n    public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) {\n      return copyEnabled\n          ? super.visitParameterAnnotation(i, string, bln)\n          : new AnnotationVisitor(Opcodes.ASM9) {};\n    }\n\n    @Override\n    public void visitTypeInsn(int opcode, String typeName) {\n      switch (opcode) {\n        case Opcodes.NEW:\n          {\n            simulatedStack.push(Boolean.FALSE);\n            break;\n          }\n      }\n      if (copyEnabled) {\n        super.visitTypeInsn(opcode, typeName);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/Printer.java",
    "content": "package org.openjdk.btrace.compiler;\n\nimport java.io.PrintWriter;\nimport java.io.Writer;\nimport java.util.ArrayList;\n\nclass Printer {\n  static int debugPrintIndentLevel = 0;\n  ////////////\n  // Output //\n  ////////////\n  private final PrintWriter writer;\n  private final ArrayList<Boolean> enabledBits = new ArrayList<>();\n\n  Printer() {\n    writer = new PrintWriter(System.err);\n  }\n\n  Printer(Writer out) {\n    writer = (out instanceof PrintWriter) ? (PrintWriter) out : new PrintWriter(out);\n  }\n\n  public static int getDebugPrintIndentLevel() {\n    return debugPrintIndentLevel;\n  }\n\n  void println() {\n    if (enabled()) {\n      writer.println();\n    }\n  }\n\n  boolean enabled() {\n    return (enabledBits.isEmpty() || enabledBits.get(enabledBits.size() - 1));\n  }\n\n  void pushEnableBit(boolean enabled) {\n    enabledBits.add(enabled);\n    ++debugPrintIndentLevel;\n    // debugPrint(false, \"PUSH_ENABLED, NOW: \" + enabled());\n  }\n\n  void print(String s) {\n    if (enabled()) {\n      writer.print(s);\n      // System.out.print(s);//debug\n    }\n  }\n\n  void flush() {\n    if (enabled()) {\n      writer.flush();\n      // System.err.flush(); //debug\n    }\n  }\n\n  void popEnableBit() {\n    if (enabledBits.isEmpty()) {\n      System.err.println(\"WARNING: mismatched #ifdef/endif pairs\");\n      return;\n    }\n    enabledBits.remove(enabledBits.size() - 1);\n    --debugPrintIndentLevel;\n    // debugPrint(false, \"POP_ENABLED, NOW: \" + enabled());\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/Verifier.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.compiler;\n\nimport com.sun.source.tree.AnnotationTree;\nimport com.sun.source.tree.AssignmentTree;\nimport com.sun.source.tree.ClassTree;\nimport com.sun.source.tree.CompilationUnitTree;\nimport com.sun.source.tree.ExpressionTree;\nimport com.sun.source.tree.IdentifierTree;\nimport com.sun.source.tree.Tree;\nimport com.sun.source.util.JavacTask;\nimport com.sun.source.util.SourcePositions;\nimport com.sun.source.util.TaskEvent;\nimport com.sun.source.util.TaskListener;\nimport com.sun.source.util.TreePath;\nimport com.sun.source.util.Trees;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.Messager;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.annotation.processing.SupportedSourceVersion;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ElementKind;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.util.Elements;\nimport javax.lang.model.util.Types;\nimport javax.tools.Diagnostic.Kind;\nimport org.openjdk.btrace.core.Messages;\nimport org.openjdk.btrace.core.annotations.BTrace;\n\n/**\n * An annotation processor that validates a BTrace program. Safety rules (such as no loops, no\n * new/throw etc.) are enforced. This uses javac's Tree API in addition to JSR 269.\n *\n * @author A. Sundararajan\n */\n@SupportedAnnotationTypes(\"*\")\n@SupportedSourceVersion(SourceVersion.RELEASE_8)\npublic class Verifier extends AbstractProcessor implements TaskListener {\n  private final List<String> classNames = new ArrayList<>();\n  private final List<CompilationUnitTree> compUnits = new ArrayList<>();\n  private final AttributionTaskListener listener = new AttributionTaskListener();\n  private Trees treeUtils;\n  private ClassTree currentClass;\n\n  @Override\n  public synchronized void init(ProcessingEnvironment pe) {\n    super.init(pe);\n    treeUtils = Trees.instance(pe);\n    JavacTask task = JavacTask.instance(processingEnv);\n    task.addTaskListener(listener);\n  }\n\n  @Override\n  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n    return true;\n  }\n\n  @Override\n  public void started(TaskEvent e) {\n    if (e.getKind() == TaskEvent.Kind.ENTER) {\n      CompilationUnitTree ct = e.getCompilationUnit();\n      if (ct != null) {\n        compUnits.add(ct);\n      }\n    }\n  }\n\n  @Override\n  public void finished(TaskEvent e) {\n    if (e.getKind() != TaskEvent.Kind.ANALYZE) return;\n    if (processingEnv == null) {\n      return;\n    }\n    TypeElement elem = e.getTypeElement();\n    for (Tree t : e.getCompilationUnit().getTypeDecls()) {\n      TreePath topLevel = new TreePath(e.getCompilationUnit());\n      if (t.getKind() == Tree.Kind.CLASS) {\n        if (elem.equals(getTreeUtils().getElement(new TreePath(topLevel, t)))) {\n          currentClass = (ClassTree) t;\n          break;\n        }\n      }\n    }\n    if (currentClass != null) {\n      verify(currentClass, elem);\n    }\n  }\n\n  List<String> getClassNames() {\n    return classNames;\n  }\n\n  CompilationUnitTree getCompilationUnit() {\n    for (CompilationUnitTree ct : compUnits) {\n      for (Tree clazz : ct.getTypeDecls()) {\n        if (clazz.equals(currentClass)) {\n          return ct;\n        }\n      }\n    }\n    return null;\n  }\n\n  Trees getTreeUtils() {\n    return treeUtils;\n  }\n\n  SourcePositions getSourcePositions() {\n    return treeUtils.getSourcePositions();\n  }\n\n  ProcessingEnvironment getProcessingEnvironment() {\n    return processingEnv;\n  }\n\n  Messager getMessager() {\n    return processingEnv.getMessager();\n  }\n\n  Elements getElementUtils() {\n    return processingEnv.getElementUtils();\n  }\n\n  Types getTypeUtils() {\n    return processingEnv.getTypeUtils();\n  }\n\n  Locale getLocale() {\n    return processingEnv.getLocale();\n  }\n\n  String annotationName(AnnotationTree at) {\n    TreePath tp = getTreeUtils().getPath(getCompilationUnit(), at.getAnnotationType());\n    Element el = getTreeUtils().getElement(tp);\n    if (el == null || el.getKind() != ElementKind.ANNOTATION_TYPE) {\n      return null;\n    }\n    return ((TypeElement) el).getQualifiedName().toString();\n  }\n\n  // verify each BTrace class\n  private void verify(ClassTree ct, Element topElement) {\n    currentClass = ct;\n    CompilationUnitTree cut = getCompilationUnit();\n    String className = ct.getSimpleName().toString();\n    ExpressionTree pkgName = cut.getPackageName();\n    if (pkgName != null) {\n      className = pkgName + \".\" + className;\n    }\n    classNames.add(className);\n    if (hasTrustedAnnotation(ct, topElement)) {\n      return;\n    }\n    ct.accept(new VerifierVisitor(this, topElement), null);\n  }\n\n  /** Detects if the class is annotated as @BTrace(trusted=true). */\n  private boolean hasTrustedAnnotation(ClassTree ct, Element topElement) {\n    for (AnnotationTree at : ct.getModifiers().getAnnotations()) {\n      String annFqn = annotationName(at);\n      if (!BTrace.class.getName().equals(annFqn)) {\n        continue;\n      }\n      // now we have @BTrace, look for unsafe = xxx or trusted = xxx\n      for (ExpressionTree ext : at.getArguments()) {\n        if (ext.getKind() != Tree.Kind.ASSIGNMENT) {\n          continue;\n        }\n        AssignmentTree assign = (AssignmentTree) ext;\n        String name = ((IdentifierTree) assign.getVariable()).getName().toString();\n        if (!\"unsafe\".equals(name) && !\"trusted\".equals(name)) {\n          continue;\n        }\n        // now rhs is the value of @BTrace.unsafe.\n        // The value can be complex (!!true, 1 == 2, etc.) - we support only booleans\n        String val = assign.getExpression().toString();\n        if (\"true\".equals(val)) {\n          return true; // bingo!\n        } else if (!\"false\".equals(val)) {\n          processingEnv\n              .getMessager()\n              .printMessage(Kind.WARNING, Messages.get(\"no.complex.unsafe.value\"), topElement);\n        }\n      }\n    }\n    return false;\n  }\n\n  /** A task listener that invokes the processor whenever a class is fully analyzed. */\n  private final class AttributionTaskListener implements TaskListener {\n\n    @Override\n    public void finished(TaskEvent e) {\n      if (e.getKind() != TaskEvent.Kind.ANALYZE) return;\n      TypeElement elem = e.getTypeElement();\n      TreePath topLevel = new TreePath(e.getCompilationUnit());\n      for (Tree t : e.getCompilationUnit().getTypeDecls()) {\n        if (t.getKind() == Tree.Kind.CLASS) {\n          if (elem.equals(getTreeUtils().getElement(new TreePath(topLevel, t)))) {\n            currentClass = (ClassTree) t;\n            break;\n          }\n        }\n      }\n      if (currentClass != null) {\n        verify(currentClass, elem);\n      }\n    }\n\n    @Override\n    public void started(TaskEvent e) {}\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/VerifierVisitor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.compiler;\n\nimport com.sun.source.tree.AnnotationTree;\nimport com.sun.source.tree.AssertTree;\nimport com.sun.source.tree.AssignmentTree;\nimport com.sun.source.tree.CatchTree;\nimport com.sun.source.tree.ClassTree;\nimport com.sun.source.tree.CompilationUnitTree;\nimport com.sun.source.tree.CompoundAssignmentTree;\nimport com.sun.source.tree.DoWhileLoopTree;\nimport com.sun.source.tree.EnhancedForLoopTree;\nimport com.sun.source.tree.ExpressionTree;\nimport com.sun.source.tree.ForLoopTree;\nimport com.sun.source.tree.MemberSelectTree;\nimport com.sun.source.tree.MethodInvocationTree;\nimport com.sun.source.tree.MethodTree;\nimport com.sun.source.tree.ModifiersTree;\nimport com.sun.source.tree.NewArrayTree;\nimport com.sun.source.tree.NewClassTree;\nimport com.sun.source.tree.ReturnTree;\nimport com.sun.source.tree.SynchronizedTree;\nimport com.sun.source.tree.ThrowTree;\nimport com.sun.source.tree.Tree;\nimport com.sun.source.tree.TryTree;\nimport com.sun.source.tree.VariableTree;\nimport com.sun.source.tree.WhileLoopTree;\nimport com.sun.source.util.SourcePositions;\nimport com.sun.source.util.TreePath;\nimport com.sun.source.util.TreeScanner;\nimport org.openjdk.btrace.core.Messages;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Injected;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.OnError;\nimport org.openjdk.btrace.core.annotations.OnExit;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Sampled;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ElementKind;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.Name;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\nimport javax.tools.Diagnostic;\nimport java.net.URL;\nimport java.net.URLDecoder;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Properties;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.EnumSet;\nimport org.openjdk.btrace.core.extensions.Permission;\n \n\n/**\n * This class tree visitor validates a BTrace program's ClassTree.\n *\n * @author A. Sundararajan\n */\npublic class VerifierVisitor extends TreeScanner<Void, Void> {\n  private static final String ON_ERROR_TYPE = OnError.class.getName();\n  private static final String ON_EXIT_TYPE = OnExit.class.getName();\n  private static final String THROWABLE_TYPE = Throwable.class.getName();\n\n  private final Verifier verifier;\n  private String className;\n  private String fqn;\n  private boolean insideMethod;\n\n  private boolean shortSyntax = false;\n  // Legacy service type mirrors removed. Only Extension-based checks remain.\n  private TypeMirror extensionTm = null;\n\n  private boolean isInAnnotation = false;\n\n  private final Set<String> eventFieldNames = new HashSet<>();\n  private final Set<String> servicePackages = new HashSet<>();\n  private final Set<String> injectedServiceTypes = new HashSet<>();\n\n  /** Permissions required by extensions used in this probe */\n  private final EnumSet<Permission> requiredPermissions = EnumSet.noneOf(Permission.class);\n\n  // Probe-declared permissions removed; permissions enforced via manifest/runtime grants.\n\n  private final TreeScanner<Void, Void> jfrFieldNameCollector =\n      new TreeScanner<Void, Void>() {\n        @Override\n        public Void visitAnnotation(AnnotationTree node, Void o) {\n          String annType = node.getAnnotationType().toString();\n          if (annType.endsWith(\"Event\")) {\n            for (ExpressionTree et : node.getArguments()) {\n              AssignmentTree t = (AssignmentTree) et;\n              String name = t.getVariable().toString();\n              if (name.equals(\"fields\")) {\n                processEventFields(t);\n              }\n            }\n          }\n          return super.visitAnnotation(node, o);\n        }\n      };\n\n  public VerifierVisitor(Verifier verifier, Element clzElement) {\n    this.verifier = verifier;\n    // Legacy service types are no longer referenced at compile time.\n    TypeElement extensionElement =\n        verifier.getElementUtils().getTypeElement(\"org.openjdk.btrace.core.extensions.Extension\");\n    if (extensionElement != null) {\n      extensionTm = extensionElement.asType();\n    }\n  }\n\n  @Override\n  public Void visitMethodInvocation(MethodInvocationTree node, Void v) {\n    Element e = getElement(node);\n    if (e != null\n        && (e.getKind() == ElementKind.METHOD || e.getKind() == ElementKind.CONSTRUCTOR)) {\n      String name = e.getSimpleName().toString();\n\n      // allow constructor calls\n      if (name.equals(\"<init>\")) {\n        return super.visitMethodInvocation(node, v);\n      }\n\n      TypeElement parent = null;\n      do {\n        parent = (TypeElement) e.getEnclosingElement();\n      } while (parent != null\n          && (parent.getKind() != ElementKind.CLASS && parent.getKind() != ElementKind.INTERFACE));\n\n      if (parent != null) {\n        TypeMirror tm = parent.asType();\n        String typeName = tm.toString();\n\n        if (isSameClass(typeName)) {\n          return super.visitMethodInvocation(node, v);\n        }\n        if (isBTraceClass(typeName)) {\n          if (typeName.contains(\"BTraceUtils\")) {\n            if (e.getSimpleName().contentEquals(\"setEventField\")) {\n              String nameValue = node.getArguments().get(1).toString();\n              if (!eventFieldNames.contains(nameValue)) {\n                reportError(\"jfr.event.invalid.field\", node.getArguments().get(1));\n              }\n            }\n          }\n          return super.visitMethodInvocation(node, v);\n        }\n        // Allow extension APIs and injected service-derived types\n        // Allow direct calls on injected extensions as well\n        if (extensionTm != null && verifier.getTypeUtils().isSubtype(tm, extensionTm)) {\n          return super.visitMethodInvocation(node, v);\n        }\n        // Also allow calls on any field types annotated with @Injected\n        // and on types in the same package/sub-packages as injected services\n        if (injectedServiceTypes.contains(typeName) || isServiceDerivedType(typeName)) {\n          return super.visitMethodInvocation(node, v);\n        }\n      }\n    }\n    reportError(\"no.method.calls\", node);\n    return super.visitMethodInvocation(node, v);\n  }\n\n  private boolean isServiceDerivedType(String typeName) {\n    // Check if this type is in the same package as any registered service\n    // This makes the verifier cooperate with the extension system automatically\n    for (String servicePackage : servicePackages) {\n      if (typeName.startsWith(servicePackage + \".\")) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private boolean isSameClass(String typeName) {\n    return fqn.equals(typeName);\n  }\n\n  private boolean isBTraceClass(String typeName) {\n    return typeName.equals(\"org.openjdk.btrace.core.BTraceUtils\")\n        || typeName.startsWith(\"org.openjdk.btrace.core.BTraceUtils.\");\n  }\n\n  @Override\n  public Void visitAssert(AssertTree node, Void v) {\n    reportError(\"no.asserts\", node);\n    return super.visitAssert(node, v);\n  }\n\n  @Override\n  public Void visitAssignment(AssignmentTree node, Void v) {\n    checkLValue(node.getVariable());\n    return super.visitAssignment(node, v);\n  }\n\n  @Override\n  public Void visitCompoundAssignment(CompoundAssignmentTree node, Void v) {\n    checkLValue(node.getVariable());\n    return super.visitCompoundAssignment(node, v);\n  }\n\n  @Override\n  public Void visitCatch(CatchTree node, Void v) {\n    reportError(\"no.catch\", node);\n    return super.visitCatch(node, v);\n  }\n\n  @Override\n  public Void visitClass(ClassTree node, Void v) {\n    // check for local class\n    if (insideMethod) {\n      reportError(\"no.local.class\", node);\n    }\n\n    // check for short BTrace syntax (inferring redundant access qualifiers)\n    Set<Modifier> mods = node.getModifiers().getFlags();\n    if (!mods.contains(Modifier.PRIVATE)\n        && !mods.contains(Modifier.PROTECTED)\n        && !mods.contains(Modifier.PUBLIC)) {\n      shortSyntax = true;\n    }\n    // check for inner and nested class\n    List<? extends Tree> members = node.getMembers();\n    for (Tree m : members) {\n      if (m.getKind() == Tree.Kind.CLASS) {\n        reportError(\"no.nested.class\", m);\n      }\n\n      if (m.getKind() == Tree.Kind.VARIABLE) {\n        VariableTree vt = (VariableTree) m;\n        boolean isStatic = isStatic(vt.getModifiers().getFlags());\n        if (shortSyntax) {\n          if (isStatic) {\n            reportError(\"no.static.variables\", m);\n          }\n        } else {\n          if (!isStatic) {\n            reportError(\"no.instance.variables\", m);\n          }\n        }\n      }\n    }\n\n    // should extend java.lang.Object\n    Tree superClass = node.getExtendsClause();\n    if (superClass != null) {\n      String name = superClass.toString();\n      if (!name.equals(\"Object\") && !name.equals(\"java.lang.Object\")) {\n        reportError(\"object.superclass.required\", superClass);\n      }\n    }\n\n    // should not implement interfaces\n    List<? extends Tree> interfaces = node.getImplementsClause();\n    if (interfaces != null && interfaces.size() > 0) {\n      reportError(\"no.interface.implementation\", interfaces.get(0));\n    }\n\n    ModifiersTree mt = node.getModifiers();\n    if (!shortSyntax && !isPublic(mt.getFlags())) {\n      reportError(\"class.should.be.public\", node);\n    }\n    List<? extends AnnotationTree> anno = mt.getAnnotations();\n    if (anno != null && !anno.isEmpty()) {\n      String btrace = BTrace.class.getName();\n      boolean isBTrace = false;\n      for (AnnotationTree at : anno) {\n        String name = at.getAnnotationType().toString();\n        if (name.equals(btrace) || name.equals(\"BTrace\")) {\n          isBTrace = true;\n        }\n        // RequestPermission annotations removed; nothing to collect here.\n      }\n      if (isBTrace) {\n        String oldClassName = className;\n        try {\n          className = node.getSimpleName().toString();\n          fqn = getElement(node).asType().toString();\n          Void result = super.visitClass(node, v);\n          // Permissions are enforced against agent grants at runtime.\n          return result;\n        } finally {\n          className = oldClassName;\n        }\n      }\n    }\n    reportError(\"not.a.btrace.program\", node);\n    return null;\n  }\n\n  @Override\n  public Void visitDoWhileLoop(DoWhileLoopTree node, Void v) {\n    reportError(\"no.do.while\", node);\n    return super.visitDoWhileLoop(node, v);\n  }\n\n  @Override\n  public Void visitEnhancedForLoop(EnhancedForLoopTree node, Void v) {\n    reportError(\"no.enhanced.for\", node);\n    return super.visitEnhancedForLoop(node, v);\n  }\n\n  @Override\n  public Void visitForLoop(ForLoopTree node, Void v) {\n    reportError(\"no.for.loop\", node);\n    return super.visitForLoop(node, v);\n  }\n\n  @Override\n  public Void visitMethod(MethodTree node, Void v) {\n    boolean oldInsideMethod = insideMethod;\n    insideMethod = true;\n    try {\n      Name name = node.getName();\n      if (name.contentEquals(\"<init>\")) {\n        return super.visitMethod(node, v);\n      } else {\n        checkSampling(node);\n\n        if (isExitHandler(node)) {\n          if (node.getParameters().size() != 1\n              || !\"int\".equals(node.getParameters().get(0).getType().toString())) {\n            reportError(\"onexit.invalid\", node);\n            return super.visitMethod(node, v);\n          }\n        }\n        if (isErrorHandler(node)) {\n          Element thrElement = getElement(node.getParameters().get(0).getType());\n          if (node.getParameters().size() != 1 || !THROWABLE_TYPE.equals(thrElement.toString())) {\n            reportError(\"onerror.invalid\", node);\n          }\n        }\n\n        for (VariableTree vt : node.getParameters()) {\n          vt.accept(\n              new TreeScanner<Void, Void>() {\n                @Override\n                public Void visitAnnotation(AnnotationTree at, Void p) {\n                  isInAnnotation = true;\n                  try {\n                    return super.visitAnnotation(at, p);\n                  } finally {\n                    isInAnnotation = false;\n                  }\n                }\n              },\n              null);\n        }\n\n        Set<Modifier> flags = node.getModifiers().getFlags();\n        if (shortSyntax) {\n          if (isStatic(flags)) {\n            reportError(\"no.static.method\", node);\n          }\n          if (isSynchronized(flags)) {\n            reportError(\"no.synchronized.methods\", node);\n          }\n        } else {\n          boolean isStatic = isStatic(flags);\n          if (isStatic) {\n            boolean isPublic = isPublic(node.getModifiers().getFlags());\n            if (isPublic) {\n              if (isSynchronized(flags)) {\n                reportError(\"no.synchronized.methods\", node);\n              }\n            } else {\n              // force the \"public\" modifier only on the annotated methods\n              if (isAnnotated(node)) {\n                reportError(\"method.should.be.public\", node);\n              }\n            }\n          } else {\n            reportError(\"no.instance.method\", node);\n          }\n        }\n\n        node.accept(jfrFieldNameCollector, null);\n\n        return super.visitMethod(node, v);\n      }\n    } finally {\n      insideMethod = oldInsideMethod;\n    }\n  }\n\n  private void addEventFieldNames(AnnotationTree at) {\n    for (ExpressionTree et1 : at.getArguments()) {\n      addEventFieldName((AssignmentTree) et1);\n    }\n  }\n\n  private void addEventFieldName(AssignmentTree assignmentTree) {\n    String varName = assignmentTree.getVariable().toString();\n    if (varName.equals(\"name\")) {\n      eventFieldNames.add(assignmentTree.getExpression().toString());\n    }\n  }\n\n  @Override\n  public Void visitNewArray(NewArrayTree node, Void v) {\n    if (!isInAnnotation) {\n      reportError(\"no.array.creation\", node);\n    }\n    return super.visitNewArray(node, v);\n  }\n\n  @Override\n  public Void visitNewClass(NewClassTree node, Void v) {\n    Element e = getElement(node);\n    TypeElement te = (TypeElement) e.getEnclosingElement();\n    reportError(\"no.new.object\", node);\n    return super.visitNewClass(node, v);\n  }\n\n  @Override\n  public Void visitReturn(ReturnTree node, Void v) {\n    if (node.getExpression() != null) {\n      TreePath tp = verifier.getTreeUtils().getPath(verifier.getCompilationUnit(), node);\n      while (tp != null) {\n        tp = tp.getParentPath();\n        Tree leaf = tp.getLeaf();\n        if (leaf.getKind() == Tree.Kind.METHOD) {\n          if (isAnnotated((MethodTree) leaf)) {\n            reportError(\"return.type.should.be.void\", node);\n          } else {\n            return super.visitReturn(node, v);\n          }\n        }\n      }\n    }\n    return super.visitReturn(node, v);\n  }\n\n  @Override\n  public Void visitMemberSelect(MemberSelectTree node, Void v) {\n    if (!isInAnnotation) {\n      if (node.getIdentifier().contentEquals(\"class\")) {\n        TypeMirror tm = getType(node.getExpression());\n        String typeName = tm != null ? tm.toString() : \"\";\n        // Allow class literals only for @Injected service types\n        if (!injectedServiceTypes.contains(typeName)) {\n          reportError(\"no.class.literals\", node);\n        }\n      }\n    }\n    return super.visitMemberSelect(node, v);\n  }\n\n  @Override\n  public Void visitAnnotation(AnnotationTree node, Void unused) {\n    try {\n      isInAnnotation = true;\n      return super.visitAnnotation(node, unused);\n    } finally {\n      isInAnnotation = false;\n    }\n  }\n\n  @Override\n  public Void visitSynchronized(SynchronizedTree node, Void v) {\n    reportError(\"no.synchronized.blocks\", node);\n    return super.visitSynchronized(node, v);\n  }\n\n  @Override\n  public Void visitThrow(ThrowTree node, Void v) {\n    reportError(\"no.throw\", node);\n    return super.visitThrow(node, v);\n  }\n\n  @Override\n  public Void visitTry(TryTree node, Void v) {\n    reportError(\"no.try\", node);\n    return super.visitTry(node, v);\n  }\n\n  @Override\n  public Void visitVariable(VariableTree vt, Void p) {\n    VariableElement ve = (VariableElement) getElement(vt);\n\n    if (ve.getEnclosingElement().getKind() == ElementKind.CLASS) {\n      // only applying to fields\n      Injected injected = ve.getAnnotation(Injected.class);\n      if (injected != null) {\n        // Track the injected service/interface type and its package for later method-call checks\n        String serviceTypeName = ve.asType().toString();\n        injectedServiceTypes.add(serviceTypeName);\n        int lastDot = serviceTypeName.lastIndexOf('.');\n        if (lastDot > 0) {\n          String servicePackage = serviceTypeName.substring(0, lastDot);\n          servicePackages.add(servicePackage);\n        }\n\n        // Validate that the injected service type is declared by some extension\n        if (!isDeclaredExtensionService(serviceTypeName)) {\n          reportError(\"invalid.injected.service\", vt);\n        }\n        if (vt.getInitializer() != null) {\n          reportError(\"injected.no.initializer\", vt.getInitializer());\n        }\n        // Best effort: if the field type is itself an Extension subtype, collect permissions\n        if (extensionTm != null && verifier.getTypeUtils().isSubtype(ve.asType(), extensionTm)) {\n          collectExtensionPermissions(ve.asType());\n        }\n      } else {\n        // JFR field name collection still applies for non-injected fields\n        vt.accept(jfrFieldNameCollector, null);\n      }\n    }\n\n    return super.visitVariable(vt, p);\n  }\n\n  /**\n   * Returns true if the given service class name is declared by any extension.\n   *\n   * Compile-time validation notes:\n   * - This check operates without loading classes. It inspects extension metadata\n   *   (BTrace-Extension-Services in MANIFEST.MF and legacy META-INF/btrace-extension.properties)\n   *   to verify that an @Injected service type is declared by some extension.\n   * - It complements the bytecode-time check in instr (BTraceProbeNode) and the runtime\n   *   reflection-based validation in the agent (Client#validateDeclaredServices). The latter\n   *   ensures correctness under the actual runtime classloader/JPMS environment.\n   */\n  private boolean isDeclaredExtensionService(String serviceClassName) {\n    String resourceName = serviceClassName.replace('.', '/') + \".class\";\n    ClassLoader cl = Thread.currentThread().getContextClassLoader();\n    if (cl == null) {\n      cl = getClass().getClassLoader();\n    }\n    try {\n      URL res = cl != null ? cl.getResource(resourceName) : null;\n      if (res != null && \"jar\".equals(res.getProtocol())) {\n        String spec = res.getFile();\n        int idx = spec.indexOf('!');\n        if (idx > 0) {\n          String jarUrl = spec.substring(0, idx);\n          if (jarUrl.startsWith(\"file:\")) {\n            jarUrl = jarUrl.substring(5);\n          }\n          String jarPath = URLDecoder.decode(jarUrl, StandardCharsets.UTF_8.name());\n          if (declaresServiceInJar(jarPath, serviceClassName)) {\n            return true;\n          }\n        }\n      }\n      // Fallback: scan system classpath jars\n      String cp = System.getProperty(\"java.class.path\", \"\");\n      String[] parts = cp.split(java.io.File.pathSeparator);\n      for (String p : parts) {\n        if (p.endsWith(\".jar\")) {\n          try {\n            if (declaresServiceInJar(p, serviceClassName)) {\n              return true;\n            }\n          } catch (Exception ignored) {\n          }\n        }\n      }\n    } catch (Exception ignored) {\n    }\n    return false;\n  }\n\n  private boolean declaresServiceInJar(String jarPath, String serviceClassName) {\n    try (JarFile jf = new JarFile(jarPath)) {\n      Manifest mf = jf.getManifest();\n      if (mf != null) {\n        Attributes attrs = mf.getMainAttributes();\n        String services = attrs.getValue(\"BTrace-Extension-Services\");\n        if (services != null && !services.trim().isEmpty()) {\n          for (String s : services.split(\"[,\\\\s]+\")) {\n            if (serviceClassName.equals(s.trim())) {\n              return true;\n            }\n          }\n        }\n      }\n      java.util.zip.ZipEntry props = jf.getEntry(\"META-INF/btrace-extension.properties\");\n      if (props != null) {\n        Properties pr = new Properties();\n        try (java.io.InputStream is = jf.getInputStream(props)) {\n          pr.load(is);\n        }\n        String services = pr.getProperty(\"services\");\n        if (services != null && !services.trim().isEmpty()) {\n          for (String s : services.split(\"[,\\\\s]+\")) {\n            if (serviceClassName.equals(s.trim())) {\n              return true;\n            }\n          }\n        }\n      }\n    } catch (Exception ignored) {\n    }\n    return false;\n  }\n\n  private void processEventFields(AssignmentTree t) {\n    if (t.getExpression() instanceof AnnotationTree) {\n      AnnotationTree at = (AnnotationTree) t.getExpression();\n      addEventFieldNames(at);\n    } else if (t.getExpression() instanceof NewArrayTree) {\n      for (ExpressionTree et2 : ((NewArrayTree) t.getExpression()).getInitializers()) {\n        AnnotationTree at = (AnnotationTree) et2;\n        addEventFieldNames(at);\n      }\n    }\n  }\n\n  @Override\n  public Void visitWhileLoop(WhileLoopTree node, Void v) {\n    reportError(\"no.while.loop\", node);\n    return super.visitWhileLoop(node, v);\n  }\n\n  @Override\n  public Void visitOther(Tree node, Void v) {\n    reportError(\"no.other\", node);\n    return super.visitOther(node, v);\n  }\n\n  private boolean isStatic(Set<Modifier> modifiers) {\n    for (Modifier m : modifiers) {\n      if (m == Modifier.STATIC) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private boolean isSynchronized(Set<Modifier> modifiers) {\n    for (Modifier m : modifiers) {\n      if (m == Modifier.SYNCHRONIZED) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private boolean isPublic(Set<Modifier> modifiers) {\n    for (Modifier m : modifiers) {\n      if (m == Modifier.PUBLIC) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private boolean isErrorHandler(MethodTree node) {\n    ModifiersTree mt = node.getModifiers();\n    List<? extends AnnotationTree> annos = mt.getAnnotations();\n    for (AnnotationTree at : annos) {\n      String annFqn = verifier.annotationName(at);\n      if (ON_ERROR_TYPE.equals(annFqn)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private boolean isExitHandler(MethodTree node) {\n    ModifiersTree mt = node.getModifiers();\n    List<? extends AnnotationTree> annos = mt.getAnnotations();\n    for (AnnotationTree at : annos) {\n      String annFqn = verifier.annotationName(at);\n      if (ON_EXIT_TYPE.equals(annFqn)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private boolean isAnnotated(MethodTree node) {\n    ModifiersTree mt = node.getModifiers();\n    List<? extends AnnotationTree> annos = mt.getAnnotations();\n    for (AnnotationTree at : annos) {\n      String annFqn = verifier.annotationName(at);\n      if (annFqn != null && annFqn.startsWith(\"org.openjdk.btrace.core.annotations\")) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private void checkSampling(MethodTree node) {\n    ExecutableElement ee = (ExecutableElement) getElement(node);\n\n    Sampled s = ee.getAnnotation(Sampled.class);\n    OnMethod om = ee.getAnnotation(OnMethod.class);\n\n    if (s != null && om != null) {\n      Kind k = om.location().value();\n      switch (k) {\n        case ENTRY:\n        case RETURN:\n        case ERROR:\n        case CALL:\n          {\n            return;\n          }\n        default:\n          {\n            // noop\n          }\n      }\n      reportError(\"sampler.invalid.location\", node);\n    }\n  }\n\n  private void checkLValue(Tree variable) {\n    if (variable.getKind() == Tree.Kind.ARRAY_ACCESS) {\n      reportError(\"no.assignment\", variable);\n      return;\n    }\n\n    if (variable.getKind() != Tree.Kind.IDENTIFIER) {\n      if (className != null) {\n        String name = variable.toString();\n        name = name.substring(0, name.lastIndexOf('.'));\n        if (!className.equals(name)) {\n          reportError(\"no.assignment\", variable);\n        }\n      } else {\n        reportError(\"no.assignment\", variable);\n      }\n    }\n  }\n\n  private void reportError(String msg, Tree node) {\n    SourcePositions srcPos = verifier.getSourcePositions();\n    CompilationUnitTree compUnit = verifier.getCompilationUnit();\n    if (compUnit != null) {\n      long pos = srcPos.getStartPosition(compUnit, node);\n      long line = compUnit.getLineMap().getLineNumber(pos);\n      String name = compUnit.getSourceFile().getName();\n      Element e = getElement(node);\n      msg = String.format(\"%s:%d:%s [%s]\", name, line, Messages.get(msg), e);\n      verifier.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);\n    } else {\n      verifier.getMessager().printMessage(Diagnostic.Kind.ERROR, msg);\n    }\n  }\n\n  private Element getElement(Tree t) {\n    TreePath tp = verifier.getTreeUtils().getPath(verifier.getCompilationUnit(), t);\n    Element e = verifier.getTreeUtils().getElement(tp);\n    if (e == null) {\n      if (t.getKind() == Tree.Kind.NEW_CLASS) {\n        e =\n            verifier\n                .getTreeUtils()\n                .getElement(new TreePath(tp, ((NewClassTree) t).getIdentifier()));\n      }\n      if (t.getKind() == Tree.Kind.THROW) {\n        e = verifier.getTreeUtils().getElement(new TreePath(tp, ((ThrowTree) t).getExpression()));\n      }\n      if (e == null) {\n        verifier.getMessager().printMessage(Diagnostic.Kind.ERROR, t.toString());\n      }\n    }\n    return e;\n  }\n\n  private TypeMirror getType(Tree t) {\n    TreePath tp = verifier.getTreeUtils().getPath(verifier.getCompilationUnit(), t);\n    return verifier.getTreeUtils().getTypeMirror(tp);\n  }\n\n  \n\n\n  // Collect extension permissions from manifest (canonical). Legacy annotations removed.\n  private void collectExtensionPermissions(TypeMirror extensionType) {\n    Element extensionElement = verifier.getTypeUtils().asElement(extensionType);\n    if (extensionElement == null) {\n      return;\n    }\n\n\n    // Also try to read permissions from the extension API JAR manifest\n    // Attribute: BTrace-Extension-Permissions: CSV of Permission names\n    try {\n      String className = extensionType.toString();\n      String resourceName = className.replace('.', '/') + \".class\";\n      ClassLoader cl = Thread.currentThread().getContextClassLoader();\n      if (cl == null) {\n        cl = getClass().getClassLoader();\n      }\n      URL res = cl != null ? cl.getResource(resourceName) : null;\n      if (res != null && \"jar\".equals(res.getProtocol())) {\n        String spec = res.getFile();\n        int idx = spec.indexOf('!');\n        if (idx > 0) {\n          String jarUrl = spec.substring(0, idx);\n          if (jarUrl.startsWith(\"file:\")) {\n            jarUrl = jarUrl.substring(5);\n          }\n          String jarPath = URLDecoder.decode(jarUrl, StandardCharsets.UTF_8.name());\n          try (JarFile jf = new JarFile(jarPath)) {\n            Manifest mf = jf.getManifest();\n            if (mf != null) {\n              Attributes attrs = mf.getMainAttributes();\n              String perms = attrs.getValue(\"BTrace-Extension-Permissions\");\n              if (perms != null && !perms.trim().isEmpty()) {\n                String[] parts = perms.split(\"[,\\\\s]+\");\n                for (String p : parts) {\n                  try {\n                    requiredPermissions.add(Permission.valueOf(p.trim()));\n                  } catch (IllegalArgumentException ignored) {\n                    // ignore unknown entries\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n    } catch (Exception ignored) {\n      // Best-effort only; ignore any IO errors\n    }\n  }\n\n  // No compile-time check for probe-declared permissions; runtime grants enforce permissions.\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/oneliner/OnelinerAST.java",
    "content": "package org.openjdk.btrace.compiler.oneliner;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\n/**\n * AST node definitions for BTrace oneliner language.\n * Represents the parsed structure of a oneliner expression.\n */\npublic class OnelinerAST {\n\n  /** Root node of the oneliner AST */\n  public static class OnelinerNode {\n    public final ProbeClause probe;\n\n    public OnelinerNode(ProbeClause probe) {\n      this.probe = Objects.requireNonNull(probe, \"probe cannot be null\");\n    }\n  }\n\n  /** Probe clause: probe_spec [filter] action_block */\n  public static class ProbeClause {\n    public final ProbeSpec probeSpec;\n    public final Filter filter; // nullable\n    public final ActionBlock actionBlock;\n\n    public ProbeClause(ProbeSpec probeSpec, Filter filter, ActionBlock actionBlock) {\n      this.probeSpec = Objects.requireNonNull(probeSpec, \"probeSpec cannot be null\");\n      this.filter = filter; // nullable\n      this.actionBlock = Objects.requireNonNull(actionBlock, \"actionBlock cannot be null\");\n    }\n  }\n\n  /** Probe specification: class::method @location */\n  public static class ProbeSpec {\n    public final String classPattern;\n    public final String methodPattern;\n    public final Location location;\n\n    public ProbeSpec(String classPattern, String methodPattern, Location location) {\n      this.classPattern = Objects.requireNonNull(classPattern, \"classPattern cannot be null\");\n      this.methodPattern = Objects.requireNonNull(methodPattern, \"methodPattern cannot be null\");\n      this.location = Objects.requireNonNull(location, \"location cannot be null\");\n    }\n  }\n\n  /** Probe location */\n  public enum Location {\n    ENTRY,\n    RETURN,\n    ERROR\n  }\n\n  /** Filter: if predicate */\n  public static class Filter {\n    public final FilterType type;\n    public final Comparator comparator;\n    public final Object value; // Integer for duration ms, String/Integer for arg comparison\n\n    public Filter(FilterType type, Comparator comparator, Object value) {\n      this.type = Objects.requireNonNull(type, \"type cannot be null\");\n      this.comparator = Objects.requireNonNull(comparator, \"comparator cannot be null\");\n      this.value = Objects.requireNonNull(value, \"value cannot be null\");\n    }\n  }\n\n  /** Filter type */\n  public enum FilterType {\n    DURATION, // duration>100ms\n    ARG_COMPARE // args[0]==\"value\"\n  }\n\n  /** Comparison operator */\n  public enum Comparator {\n    GT,\n    LT,\n    EQ,\n    GTE,\n    LTE,\n    NEQ\n  }\n\n  /** Action block: { action, action, ... } */\n  public static class ActionBlock {\n    public final List<Action> actions;\n\n    public ActionBlock(List<Action> actions) {\n      this.actions = new ArrayList<>(Objects.requireNonNull(actions, \"actions cannot be null\"));\n      if (this.actions.isEmpty()) {\n        throw new IllegalArgumentException(\"Action block cannot be empty\");\n      }\n    }\n  }\n\n  /** Base interface for all actions */\n  public interface Action {}\n\n  /** Print action: print [identifier, ...] */\n  public static class PrintAction implements Action {\n    public final List<String> args; // nullable for bare \"print\"\n\n    public PrintAction(List<String> args) {\n      this.args = args != null ? new ArrayList<>(args) : new ArrayList<>();\n    }\n  }\n\n  /** Count action: count */\n  public static class CountAction implements Action {\n    public CountAction() {}\n  }\n\n  /** Time action: time */\n  public static class TimeAction implements Action {\n    public TimeAction() {}\n  }\n\n  /** Stack action: stack [(depth)] */\n  public static class StackAction implements Action {\n    public final Integer depth; // nullable for default depth\n\n    public StackAction(Integer depth) {\n      if (depth != null && depth <= 0) {\n        throw new IllegalArgumentException(\"Stack depth must be positive, got: \" + depth);\n      }\n      this.depth = depth;\n    }\n  }\n\n  /** For arg filters: args[index] */\n  public static class ArgFilter extends Filter {\n    public final int argIndex;\n\n    public ArgFilter(int argIndex, Comparator comparator, Object value) {\n      super(FilterType.ARG_COMPARE, comparator, value);\n      if (argIndex < 0) {\n        throw new IllegalArgumentException(\"Argument index must be non-negative, got: \" + argIndex);\n      }\n      this.argIndex = argIndex;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/oneliner/OnelinerCodeGenerator.java",
    "content": "package org.openjdk.btrace.compiler.oneliner;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerAST.*;\n\n/** Generates BTrace Java source code from oneliner AST */\npublic class OnelinerCodeGenerator {\n\n  private static final String INDENT = \"  \";\n  private static final String DEFAULT_CLASS_NAME = \"BTraceOneliner\";\n\n  /**\n   * Generate Java source code from a oneliner AST using the default class name.\n   *\n   * @param node The parsed oneliner AST\n   * @return Generated BTrace Java source code\n   */\n  public static String generate(OnelinerNode node) {\n    return generate(node, DEFAULT_CLASS_NAME);\n  }\n\n  /**\n   * Generate Java source code from a oneliner AST with a custom class name.\n   *\n   * @param node The parsed oneliner AST\n   * @param className The class name to use for the generated BTrace script\n   * @return Generated BTrace Java source code\n   */\n  public static String generate(OnelinerNode node, String className) {\n    if (className == null || className.isEmpty()) {\n      className = DEFAULT_CLASS_NAME;\n    }\n    StringBuilder sb = new StringBuilder();\n\n    // Package and imports\n    sb.append(\"package org.openjdk.btrace.generated;\\n\\n\");\n    sb.append(\"import java.util.concurrent.atomic.AtomicInteger;\\n\");\n    sb.append(\"import org.openjdk.btrace.core.BTraceUtils;\\n\");\n    sb.append(\"import org.openjdk.btrace.core.annotations.*;\\n\");\n    sb.append(\"import org.openjdk.btrace.core.types.AnyType;\\n\\n\");\n\n    // Class declaration\n    sb.append(\"@BTrace\\n\");\n    sb.append(\"public class \").append(className).append(\" {\\n\\n\");\n\n    ProbeClause probe = node.probe;\n\n    // Generate fields (for count action)\n    boolean hasCountAction = hasCountAction(probe.actionBlock);\n    if (hasCountAction) {\n      sb.append(INDENT)\n          .append(\"private static final AtomicInteger counter = BTraceUtils.newAtomicInteger(0);\\n\\n\");\n    }\n\n    // Generate probe method\n    generateProbeMethod(sb, probe);\n\n    // Generate @OnEvent method (for count action)\n    if (hasCountAction) {\n      sb.append(\"\\n\");\n      sb.append(INDENT).append(\"@OnEvent\\n\");\n      sb.append(INDENT).append(\"public static void onEvent() {\\n\");\n      sb.append(INDENT).append(INDENT);\n      sb.append(\"BTraceUtils.println(\\\"count: \\\" + BTraceUtils.get(counter));\\n\");\n      sb.append(INDENT).append(\"}\\n\");\n    }\n\n    // Close class\n    sb.append(\"}\\n\");\n\n    return sb.toString();\n  }\n\n  private static void generateProbeMethod(StringBuilder sb, ProbeClause probe) {\n    ProbeSpec spec = probe.probeSpec;\n\n    // Generate @OnMethod annotation\n    sb.append(INDENT).append(\"@OnMethod(\");\n    sb.append(\"clazz=\\\"\").append(escapeJavaString(spec.classPattern)).append(\"\\\", \");\n    sb.append(\"method=\\\"\").append(escapeJavaString(spec.methodPattern)).append(\"\\\"\");\n\n    // Add location if not ENTRY\n    if (spec.location != Location.ENTRY) {\n      sb.append(\",\\n\");\n      sb.append(INDENT).append(INDENT).append(INDENT);\n      sb.append(\"location=@Location(Kind.\").append(spec.location.name()).append(\")\");\n    }\n\n    sb.append(\")\\n\");\n\n    // Generate method signature\n    sb.append(INDENT).append(\"public static void probe(\");\n\n    List<String> params = collectParameters(probe);\n    for (int i = 0; i < params.size(); i++) {\n      if (i > 0) {\n        sb.append(\", \");\n      }\n      sb.append(params.get(i));\n    }\n\n    sb.append(\") {\\n\");\n\n    // Generate method body\n    generateMethodBody(sb, probe);\n\n    // Close method\n    sb.append(INDENT).append(\"}\\n\");\n  }\n\n  private static List<String> collectParameters(ProbeClause probe) {\n    List<String> params = new ArrayList<>();\n    Set<String> seen = new HashSet<>();\n\n    // Collect parameters from filter\n    if (probe.filter != null) {\n      addFilterParameters(params, seen, probe.filter, probe.probeSpec.location);\n    }\n\n    // Collect parameters from actions\n    for (Action action : probe.actionBlock.actions) {\n      if (action instanceof PrintAction) {\n        addPrintParameters(params, seen, (PrintAction) action, probe.probeSpec.location);\n      } else if (action instanceof TimeAction) {\n        addParameter(params, seen, \"@Duration long duration\");\n      }\n    }\n\n    return params;\n  }\n\n  private static void addFilterParameters(\n      List<String> params, Set<String> seen, Filter filter, Location location) {\n    if (filter.type == FilterType.DURATION) {\n      addParameter(params, seen, \"@Duration long duration\");\n    } else if (filter.type == FilterType.ARG_COMPARE) {\n      addParameter(params, seen, \"AnyType[] args\");\n    }\n  }\n\n  private static void addPrintParameters(\n      List<String> params, Set<String> seen, PrintAction action, Location location) {\n    for (String arg : action.args) {\n      switch (arg) {\n        case \"method\":\n          addParameter(params, seen, \"@ProbeMethodName String method\");\n          break;\n        case \"class\":\n          addParameter(params, seen, \"@ProbeClassName String className\");\n          break;\n        case \"args\":\n          addParameter(params, seen, \"AnyType[] args\");\n          break;\n        case \"duration\":\n          addParameter(params, seen, \"@Duration long duration\");\n          break;\n        case \"return\":\n          addParameter(params, seen, \"@Return AnyType returnValue\");\n          break;\n        case \"self\":\n          addParameter(params, seen, \"@Self Object self\");\n          break;\n      }\n    }\n  }\n\n  private static void addParameter(List<String> params, Set<String> seen, String param) {\n    if (!seen.contains(param)) {\n      params.add(param);\n      seen.add(param);\n    }\n  }\n\n  private static void generateMethodBody(StringBuilder sb, ProbeClause probe) {\n    String indent = INDENT + INDENT;\n\n    // Generate filter if-statement\n    if (probe.filter != null) {\n      sb.append(indent).append(\"if (\");\n      generateFilterCondition(sb, probe.filter);\n      sb.append(\") {\\n\");\n      indent = INDENT + INDENT + INDENT;\n    }\n\n    // Generate actions\n    for (Action action : probe.actionBlock.actions) {\n      if (action instanceof PrintAction) {\n        generatePrintAction(sb, indent, (PrintAction) action);\n      } else if (action instanceof CountAction) {\n        sb.append(indent).append(\"BTraceUtils.incrementAndGet(counter);\\n\");\n      } else if (action instanceof TimeAction) {\n        generateTimeAction(sb, indent);\n      } else if (action instanceof StackAction) {\n        generateStackAction(sb, indent, (StackAction) action);\n      }\n    }\n\n    // Close filter if-statement\n    if (probe.filter != null) {\n      sb.append(INDENT).append(INDENT).append(\"}\\n\");\n    }\n  }\n\n  private static void generateFilterCondition(StringBuilder sb, Filter filter) {\n    if (filter.type == FilterType.DURATION) {\n      sb.append(\"duration \");\n      sb.append(comparatorToJava(filter.comparator));\n      sb.append(\" \");\n      int millis = (Integer) filter.value;\n      long nanos = millis * 1_000_000L;\n      sb.append(nanos).append(\"L\");\n    } else if (filter.type == FilterType.ARG_COMPARE) {\n      ArgFilter argFilter = (ArgFilter) filter;\n      sb.append(\"args.length > \").append(argFilter.argIndex);\n      sb.append(\" && \");\n\n      if (argFilter.value == null) {\n        sb.append(\"args[\").append(argFilter.argIndex).append(\"] \");\n        sb.append(comparatorToJava(argFilter.comparator));\n        sb.append(\" null\");\n      } else if (argFilter.value instanceof String) {\n        if (argFilter.comparator == Comparator.EQ) {\n          sb.append(\"BTraceUtils.compare(\\\"\")\n              .append(escapeJavaString((String) argFilter.value))\n              .append(\"\\\", \");\n          sb.append(\"BTraceUtils.str(args[\").append(argFilter.argIndex).append(\"]))\");\n        } else if (argFilter.comparator == Comparator.NEQ) {\n          sb.append(\"!BTraceUtils.compare(\\\"\")\n              .append(escapeJavaString((String) argFilter.value))\n              .append(\"\\\", \");\n          sb.append(\"BTraceUtils.str(args[\").append(argFilter.argIndex).append(\"]))\");\n        } else {\n          throw new IllegalArgumentException(\n              \"String comparison only supports == and !=, got: \" + argFilter.comparator);\n        }\n      } else if (argFilter.value instanceof Integer) {\n        sb.append(\"((Number)args[\").append(argFilter.argIndex).append(\"]).longValue() \");\n        sb.append(comparatorToJava(argFilter.comparator));\n        sb.append(\" \").append(argFilter.value).append(\"L\");\n      }\n    }\n  }\n\n  private static String comparatorToJava(Comparator comp) {\n    switch (comp) {\n      case GT:\n        return \">\";\n      case LT:\n        return \"<\";\n      case EQ:\n        return \"==\";\n      case GTE:\n        return \">=\";\n      case LTE:\n        return \"<=\";\n      case NEQ:\n        return \"!=\";\n      default:\n        throw new IllegalArgumentException(\"Unknown comparator: \" + comp);\n    }\n  }\n\n  private static void generatePrintAction(StringBuilder sb, String indent, PrintAction action) {\n    if (action.args.isEmpty()) {\n      // Bare \"print\" with no arguments\n      sb.append(indent).append(\"BTraceUtils.println(\\\"trace\\\");\\n\");\n    } else {\n      sb.append(indent).append(\"BTraceUtils.println(\");\n\n      for (int i = 0; i < action.args.size(); i++) {\n        if (i > 0) {\n          sb.append(\" + \\\" \\\" + \");\n        }\n        String arg = action.args.get(i);\n        switch (arg) {\n          case \"method\":\n            sb.append(\"method\");\n            break;\n          case \"class\":\n            sb.append(\"className\");\n            break;\n          case \"args\":\n            sb.append(\"BTraceUtils.str(args)\");\n            break;\n          case \"duration\":\n            sb.append(\"duration\");\n            break;\n          case \"return\":\n            sb.append(\"BTraceUtils.str(returnValue)\");\n            break;\n          case \"self\":\n            sb.append(\"BTraceUtils.str(self)\");\n            break;\n        }\n      }\n\n      sb.append(\");\\n\");\n    }\n  }\n\n  private static void generateTimeAction(StringBuilder sb, String indent) {\n    sb.append(indent)\n        .append(\"BTraceUtils.println(\\\"execution time: \\\" + (duration / 1000000) + \\\" ms\\\");\\n\");\n  }\n\n  private static void generateStackAction(StringBuilder sb, String indent, StackAction action) {\n    sb.append(indent).append(\"BTraceUtils.jstack(\");\n    if (action.depth != null) {\n      sb.append(action.depth);\n    }\n    sb.append(\");\\n\");\n  }\n\n  private static boolean hasCountAction(ActionBlock actionBlock) {\n    for (Action action : actionBlock.actions) {\n      if (action instanceof CountAction) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private static String escapeJavaString(String str) {\n    return str.replace(\"\\\\\", \"\\\\\\\\\").replace(\"\\\"\", \"\\\\\\\"\").replace(\"\\n\", \"\\\\n\").replace(\"\\t\", \"\\\\t\");\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/oneliner/OnelinerException.java",
    "content": "package org.openjdk.btrace.compiler.oneliner;\n\n/**\n * Exception thrown when parsing or validating BTrace oneliner expressions.\n * Includes position tracking for better error messages.\n */\npublic class OnelinerException extends RuntimeException {\n  private final int position;\n  private final String input;\n\n  public OnelinerException(String message, String input, int position) {\n    super(formatMessage(message, input, position));\n    this.position = position;\n    this.input = input;\n  }\n\n  public OnelinerException(String message, String input, int position, Throwable cause) {\n    super(formatMessage(message, input, position), cause);\n    this.position = position;\n    this.input = input;\n  }\n\n  public int getPosition() {\n    return position;\n  }\n\n  public String getInput() {\n    return input;\n  }\n\n  private static String formatMessage(String message, String input, int position) {\n    StringBuilder sb = new StringBuilder();\n    sb.append(\"Oneliner syntax error at position \").append(position).append(\":\\n\");\n    sb.append(input).append(\"\\n\");\n\n    if (position >= 0 && position < input.length()) {\n      for (int i = 0; i < position; i++) {\n        sb.append(\" \");\n      }\n      sb.append(\"^\\n\");\n    }\n\n    sb.append(message);\n    return sb.toString();\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/oneliner/OnelinerLexer.java",
    "content": "package org.openjdk.btrace.compiler.oneliner;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/** Tokenizer for BTrace oneliner language */\npublic class OnelinerLexer {\n\n  /** Token types */\n  public enum TokenType {\n    // Literals\n    IDENTIFIER,\n    NUMBER,\n    STRING,\n    REGEX,\n\n    // Keywords\n    IF,\n    PRINT,\n    COUNT,\n    STACK,\n    TIME,\n    ENTRY,\n    RETURN,\n    ERROR,\n\n    // Special identifiers\n    METHOD,\n    ARGS,\n    DURATION,\n    RETURN_VAL,\n    SELF,\n    CLASS,\n\n    // Symbols\n    DOUBLE_COLON,\n    AT,\n    LBRACE,\n    RBRACE,\n    LPAREN,\n    RPAREN,\n    LBRACKET,\n    RBRACKET,\n    COMMA,\n    EQ,\n    GT,\n    LT,\n    GTE,\n    LTE,\n    NEQ,\n\n    EOF\n  }\n\n  /** Token with type, value, and position */\n  public static class Token {\n    public final TokenType type;\n    public final String value;\n    public final int position;\n\n    public Token(TokenType type, String value, int position) {\n      this.type = type;\n      this.value = value;\n      this.position = position;\n    }\n\n    @Override\n    public String toString() {\n      return type + (value != null && !value.isEmpty() ? \"(\" + value + \")\" : \"\")\n          + \"@\"\n          + position;\n    }\n  }\n\n  private static final Map<String, TokenType> KEYWORDS = new HashMap<>();\n\n  static {\n    KEYWORDS.put(\"if\", TokenType.IF);\n    KEYWORDS.put(\"print\", TokenType.PRINT);\n    KEYWORDS.put(\"count\", TokenType.COUNT);\n    KEYWORDS.put(\"stack\", TokenType.STACK);\n    KEYWORDS.put(\"time\", TokenType.TIME);\n    KEYWORDS.put(\"entry\", TokenType.ENTRY);\n    KEYWORDS.put(\"return\", TokenType.RETURN_VAL);\n    KEYWORDS.put(\"error\", TokenType.ERROR);\n    KEYWORDS.put(\"method\", TokenType.METHOD);\n    KEYWORDS.put(\"args\", TokenType.ARGS);\n    KEYWORDS.put(\"duration\", TokenType.DURATION);\n    KEYWORDS.put(\"self\", TokenType.SELF);\n    KEYWORDS.put(\"class\", TokenType.CLASS);\n  }\n\n  private final String input;\n  private int pos = 0;\n\n  public OnelinerLexer(String input) {\n    this.input = input != null ? input : \"\";\n  }\n\n  /** Tokenize the entire input */\n  public List<Token> tokenize() {\n    List<Token> tokens = new ArrayList<>();\n    Token token;\n    while ((token = nextToken()).type != TokenType.EOF) {\n      tokens.add(token);\n    }\n    tokens.add(token); // add EOF\n    return tokens;\n  }\n\n  /** Get the next token */\n  public Token nextToken() {\n    skipWhitespace();\n\n    if (isEOF()) {\n      return new Token(TokenType.EOF, \"\", pos);\n    }\n\n    int startPos = pos;\n    char ch = peek();\n\n    // Two-character operators\n    if (ch == ':' && peek(1) == ':') {\n      pos += 2;\n      return new Token(TokenType.DOUBLE_COLON, \"::\", startPos);\n    }\n    if (ch == '=' && peek(1) == '=') {\n      pos += 2;\n      return new Token(TokenType.EQ, \"==\", startPos);\n    }\n    if (ch == '>' && peek(1) == '=') {\n      pos += 2;\n      return new Token(TokenType.GTE, \">=\", startPos);\n    }\n    if (ch == '<' && peek(1) == '=') {\n      pos += 2;\n      return new Token(TokenType.LTE, \"<=\", startPos);\n    }\n    if (ch == '!' && peek(1) == '=') {\n      pos += 2;\n      return new Token(TokenType.NEQ, \"!=\", startPos);\n    }\n\n    // Single-character tokens\n    switch (ch) {\n      case '@':\n        pos++;\n        return new Token(TokenType.AT, \"@\", startPos);\n      case '{':\n        pos++;\n        return new Token(TokenType.LBRACE, \"{\", startPos);\n      case '}':\n        pos++;\n        return new Token(TokenType.RBRACE, \"}\", startPos);\n      case '(':\n        pos++;\n        return new Token(TokenType.LPAREN, \"(\", startPos);\n      case ')':\n        pos++;\n        return new Token(TokenType.RPAREN, \")\", startPos);\n      case '[':\n        pos++;\n        return new Token(TokenType.LBRACKET, \"[\", startPos);\n      case ']':\n        pos++;\n        return new Token(TokenType.RBRACKET, \"]\", startPos);\n      case ',':\n        pos++;\n        return new Token(TokenType.COMMA, \",\", startPos);\n      case '>':\n        pos++;\n        return new Token(TokenType.GT, \">\", startPos);\n      case '<':\n        pos++;\n        return new Token(TokenType.LT, \"<\", startPos);\n    }\n\n    // Regex pattern /pattern/\n    if (ch == '/') {\n      return scanRegex(startPos);\n    }\n\n    // String \"value\"\n    if (ch == '\"') {\n      return scanString(startPos);\n    }\n\n    // Number\n    if (Character.isDigit(ch)) {\n      return scanNumber(startPos);\n    }\n\n    // Identifier or keyword\n    if (isIdentifierStart(ch)) {\n      return scanIdentifierOrKeyword(startPos);\n    }\n\n    throw new OnelinerException(\n        \"Unexpected character: '\" + ch + \"'\", input, pos);\n  }\n\n  private Token scanRegex(int startPos) {\n    pos++; // skip initial '/'\n    StringBuilder sb = new StringBuilder();\n    while (!isEOF() && peek() != '/') {\n      if (peek() == '\\\\' && peek(1) == '/') {\n        sb.append('/');\n        pos += 2;\n      } else {\n        sb.append(peek());\n        pos++;\n      }\n    }\n    if (isEOF()) {\n      throw new OnelinerException(\n          \"Unterminated regex pattern, expected closing '/'\", input, startPos);\n    }\n    pos++; // skip closing '/'\n    return new Token(TokenType.REGEX, sb.toString(), startPos);\n  }\n\n  private Token scanString(int startPos) {\n    pos++; // skip initial '\"'\n    StringBuilder sb = new StringBuilder();\n    while (!isEOF() && peek() != '\"') {\n      if (peek() == '\\\\') {\n        pos++;\n        if (isEOF()) {\n          throw new OnelinerException(\n              \"Unterminated string, expected closing '\\\"'\", input, startPos);\n        }\n        char escaped = peek();\n        switch (escaped) {\n          case 'n':\n            sb.append('\\n');\n            break;\n          case 't':\n            sb.append('\\t');\n            break;\n          case 'r':\n            sb.append('\\r');\n            break;\n          case '\\\\':\n            sb.append('\\\\');\n            break;\n          case '\"':\n            sb.append('\"');\n            break;\n          default:\n            sb.append(escaped);\n        }\n        pos++;\n      } else {\n        sb.append(peek());\n        pos++;\n      }\n    }\n    if (isEOF()) {\n      throw new OnelinerException(\n          \"Unterminated string, expected closing '\\\"'\", input, startPos);\n    }\n    pos++; // skip closing '\"'\n    return new Token(TokenType.STRING, sb.toString(), startPos);\n  }\n\n  private Token scanNumber(int startPos) {\n    StringBuilder sb = new StringBuilder();\n    while (!isEOF() && Character.isDigit(peek())) {\n      sb.append(peek());\n      pos++;\n    }\n    return new Token(TokenType.NUMBER, sb.toString(), startPos);\n  }\n\n  private Token scanIdentifierOrKeyword(int startPos) {\n    StringBuilder sb = new StringBuilder();\n    while (!isEOF() && isIdentifierPart(peek())) {\n      sb.append(peek());\n      pos++;\n    }\n    String value = sb.toString();\n    TokenType type = KEYWORDS.getOrDefault(value, TokenType.IDENTIFIER);\n    return new Token(type, value, startPos);\n  }\n\n  private void skipWhitespace() {\n    while (!isEOF() && Character.isWhitespace(peek())) {\n      pos++;\n    }\n  }\n\n  private boolean isEOF() {\n    return pos >= input.length();\n  }\n\n  private char peek() {\n    return peek(0);\n  }\n\n  private char peek(int offset) {\n    int index = pos + offset;\n    return index < input.length() ? input.charAt(index) : '\\0';\n  }\n\n  private boolean isIdentifierStart(char ch) {\n    return Character.isLetter(ch) || ch == '_' || ch == '*' || ch == '?';\n  }\n\n  private boolean isIdentifierPart(char ch) {\n    return Character.isLetterOrDigit(ch)\n        || ch == '_'\n        || ch == '.'\n        || ch == '*'\n        || ch == '?'\n        || ch == '$';\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/oneliner/OnelinerParser.java",
    "content": "package org.openjdk.btrace.compiler.oneliner;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerAST.*;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerLexer.Token;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerLexer.TokenType;\n\n/** Parser for BTrace oneliner language */\npublic class OnelinerParser {\n\n  private final String input;\n  private final List<Token> tokens;\n  private int current = 0;\n\n  private OnelinerParser(String input, List<Token> tokens) {\n    this.input = input;\n    this.tokens = tokens;\n  }\n\n  /** Parse a oneliner expression */\n  public static OnelinerNode parse(String input) {\n    OnelinerLexer lexer = new OnelinerLexer(input);\n    List<Token> tokens = lexer.tokenize();\n    OnelinerParser parser = new OnelinerParser(input, tokens);\n    return parser.parseOneliner();\n  }\n\n  /** oneliner = probe_spec [filter] action_block */\n  private OnelinerNode parseOneliner() {\n    ProbeSpec probeSpec = parseProbeSpec();\n    Filter filter = null;\n    if (check(TokenType.IF)) {\n      filter = parseFilter();\n    }\n    ActionBlock actionBlock = parseActionBlock();\n\n    if (!isAtEnd()) {\n      error(\"Unexpected token after action block: \" + peek().type);\n    }\n\n    ProbeClause probe = new ProbeClause(probeSpec, filter, actionBlock);\n    return new OnelinerNode(probe);\n  }\n\n  /** probe_spec = class_pattern :: method_pattern @ location */\n  private ProbeSpec parseProbeSpec() {\n    String classPattern = parsePattern(\"class pattern\");\n\n    if (!match(TokenType.DOUBLE_COLON)) {\n      error(\"Expected '::' after class pattern\");\n    }\n\n    String methodPattern = parsePattern(\"method pattern\");\n\n    if (!match(TokenType.AT)) {\n      error(\"Expected '@' before location\");\n    }\n\n    Location location = parseLocation();\n\n    return new ProbeSpec(classPattern, methodPattern, location);\n  }\n\n  /** Parse class or method pattern (supports wildcards * ? and regex /.../) */\n  private String parsePattern(String patternName) {\n    if (check(TokenType.REGEX)) {\n      String regex = advance().value;\n      return \"/\" + regex + \"/\";\n    } else if (check(TokenType.IDENTIFIER)) {\n      return advance().value;\n    } else if (check(TokenType.LT)) {\n      // Handle special method names like <init> and <clinit>\n      advance(); // consume '<'\n      if (!check(TokenType.IDENTIFIER)) {\n        error(\"Expected 'init' or 'clinit' after '<'\");\n      }\n      String methodName = advance().value;\n      if (!check(TokenType.GT)) {\n        error(\"Expected '>' after '\" + methodName + \"'\");\n      }\n      advance(); // consume '>'\n      return \"<\" + methodName + \">\";\n    } else {\n      error(\"Expected \" + patternName + \" (identifier or regex)\");\n      return null;\n    }\n  }\n\n  /** location = entry | return | error */\n  private Location parseLocation() {\n    if (match(TokenType.ENTRY)) {\n      return Location.ENTRY;\n    } else if (match(TokenType.RETURN_VAL)) {\n      return Location.RETURN;\n    } else if (match(TokenType.ERROR)) {\n      return Location.ERROR;\n    } else {\n      error(\"Expected location: entry, return, or error\");\n      return null;\n    }\n  }\n\n  /** filter = if predicate */\n  private Filter parseFilter() {\n    if (!match(TokenType.IF)) {\n      error(\"Expected 'if' keyword\");\n    }\n\n    return parsePredicate();\n  }\n\n  /** predicate = duration_predicate | arg_predicate */\n  private Filter parsePredicate() {\n    if (check(TokenType.DURATION)) {\n      return parseDurationPredicate();\n    } else if (check(TokenType.ARGS)) {\n      return parseArgPredicate();\n    } else {\n      error(\"Expected 'duration' or 'args' in filter predicate\");\n      return null;\n    }\n  }\n\n  /** duration_predicate = duration comparator number ms */\n  private Filter parseDurationPredicate() {\n    if (!match(TokenType.DURATION)) {\n      error(\"Expected 'duration'\");\n    }\n\n    Comparator comp = parseComparator();\n\n    if (!check(TokenType.NUMBER)) {\n      error(\"Expected number after comparator in duration filter\");\n    }\n    int millis = Integer.parseInt(advance().value);\n\n    if (!check(TokenType.IDENTIFIER) || !peek().value.equals(\"ms\")) {\n      error(\"Expected 'ms' after duration value\");\n    }\n    advance(); // consume 'ms'\n\n    return new Filter(FilterType.DURATION, comp, millis);\n  }\n\n  /** arg_predicate = args [ number ] comparator value */\n  private Filter parseArgPredicate() {\n    if (!match(TokenType.ARGS)) {\n      error(\"Expected 'args'\");\n    }\n\n    if (!match(TokenType.LBRACKET)) {\n      error(\"Expected '[' after 'args'\");\n    }\n\n    if (!check(TokenType.NUMBER)) {\n      error(\"Expected number for argument index\");\n    }\n    int argIndex = Integer.parseInt(advance().value);\n\n    if (!match(TokenType.RBRACKET)) {\n      error(\"Expected ']' after argument index\");\n    }\n\n    Comparator comp = parseComparator();\n\n    Object value;\n    if (check(TokenType.STRING)) {\n      value = advance().value;\n    } else if (check(TokenType.NUMBER)) {\n      value = Integer.parseInt(advance().value);\n    } else if (check(TokenType.IDENTIFIER) && peek().value.equals(\"null\")) {\n      value = null;\n      advance();\n    } else {\n      error(\"Expected string, number, or null in argument comparison\");\n      return null;\n    }\n\n    return new ArgFilter(argIndex, comp, value);\n  }\n\n  /** comparator = > | < | == | >= | <= | != */\n  private Comparator parseComparator() {\n    if (match(TokenType.GT)) {\n      return Comparator.GT;\n    } else if (match(TokenType.LT)) {\n      return Comparator.LT;\n    } else if (match(TokenType.EQ)) {\n      return Comparator.EQ;\n    } else if (match(TokenType.GTE)) {\n      return Comparator.GTE;\n    } else if (match(TokenType.LTE)) {\n      return Comparator.LTE;\n    } else if (match(TokenType.NEQ)) {\n      return Comparator.NEQ;\n    } else {\n      error(\"Expected comparison operator: >, <, ==, >=, <=, !=\");\n      return null;\n    }\n  }\n\n  /** action_block = { action [, action]* } */\n  private ActionBlock parseActionBlock() {\n    if (!match(TokenType.LBRACE)) {\n      error(\"Expected '{' to start action block\");\n    }\n\n    List<Action> actions = new ArrayList<>();\n    actions.add(parseAction());\n\n    while (match(TokenType.COMMA)) {\n      actions.add(parseAction());\n    }\n\n    if (!match(TokenType.RBRACE)) {\n      error(\"Expected '}' to end action block or ',' for another action\");\n    }\n\n    return new ActionBlock(actions);\n  }\n\n  /** action = print_action | count_action | time_action | stack_action */\n  private Action parseAction() {\n    if (check(TokenType.PRINT)) {\n      return parsePrintAction();\n    } else if (check(TokenType.COUNT)) {\n      return parseCountAction();\n    } else if (check(TokenType.TIME)) {\n      return parseTimeAction();\n    } else if (check(TokenType.STACK)) {\n      return parseStackAction();\n    } else {\n      error(\"Expected action: print, count, time, or stack\");\n      return null;\n    }\n  }\n\n  /** print_action = print [identifier [, identifier]*] */\n  private PrintAction parsePrintAction() {\n    if (!match(TokenType.PRINT)) {\n      error(\"Expected 'print'\");\n    }\n\n    List<String> args = new ArrayList<>();\n\n    // Check if there are any identifiers to print\n    if (isPrintIdentifier(peek().type)) {\n      args.add(parsePrintIdentifier());\n\n      while (match(TokenType.COMMA) && isAtEnd() == false) {\n        // Check if next token after comma is a print identifier or another action\n        if (isPrintIdentifier(peek().type)) {\n          args.add(parsePrintIdentifier());\n        } else {\n          // Put the comma back by decrementing current\n          current--;\n          break;\n        }\n      }\n    }\n\n    return new PrintAction(args);\n  }\n\n  private boolean isPrintIdentifier(TokenType type) {\n    return type == TokenType.METHOD\n        || type == TokenType.ARGS\n        || type == TokenType.DURATION\n        || type == TokenType.RETURN_VAL\n        || type == TokenType.SELF\n        || type == TokenType.CLASS;\n  }\n\n  private String parsePrintIdentifier() {\n    if (match(TokenType.METHOD)) {\n      return \"method\";\n    } else if (match(TokenType.ARGS)) {\n      return \"args\";\n    } else if (match(TokenType.DURATION)) {\n      return \"duration\";\n    } else if (match(TokenType.RETURN_VAL)) {\n      return \"return\";\n    } else if (match(TokenType.SELF)) {\n      return \"self\";\n    } else if (match(TokenType.CLASS)) {\n      return \"class\";\n    } else {\n      error(\"Expected print identifier: method, args, duration, return, self, or class\");\n      return null;\n    }\n  }\n\n  /** count_action = count */\n  private CountAction parseCountAction() {\n    if (!match(TokenType.COUNT)) {\n      error(\"Expected 'count'\");\n    }\n    return new CountAction();\n  }\n\n  /** time_action = time */\n  private TimeAction parseTimeAction() {\n    if (!match(TokenType.TIME)) {\n      error(\"Expected 'time'\");\n    }\n    return new TimeAction();\n  }\n\n  /** stack_action = stack [(number)] */\n  private StackAction parseStackAction() {\n    if (!match(TokenType.STACK)) {\n      error(\"Expected 'stack'\");\n    }\n\n    Integer depth = null;\n    if (match(TokenType.LPAREN)) {\n      if (!check(TokenType.NUMBER)) {\n        error(\"Expected number for stack depth\");\n      }\n      depth = Integer.parseInt(advance().value);\n\n      if (!match(TokenType.RPAREN)) {\n        error(\"Expected ')' after stack depth\");\n      }\n    }\n\n    return new StackAction(depth);\n  }\n\n  // Helper methods\n\n  private boolean match(TokenType... types) {\n    for (TokenType type : types) {\n      if (check(type)) {\n        advance();\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private boolean check(TokenType type) {\n    if (isAtEnd()) {\n      return false;\n    }\n    return peek().type == type;\n  }\n\n  private Token advance() {\n    if (!isAtEnd()) {\n      current++;\n    }\n    return previous();\n  }\n\n  private boolean isAtEnd() {\n    return peek().type == TokenType.EOF;\n  }\n\n  private Token peek() {\n    return tokens.get(current);\n  }\n\n  private Token previous() {\n    return tokens.get(current - 1);\n  }\n\n  private void error(String message) {\n    int position = isAtEnd() ? input.length() : peek().position;\n    throw new OnelinerException(message, input, position);\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/main/java/org/openjdk/btrace/compiler/oneliner/OnelinerValidator.java",
    "content": "package org.openjdk.btrace.compiler.oneliner;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.regex.Pattern;\nimport java.util.regex.PatternSyntaxException;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerAST.*;\n\n/** Semantic validator for BTrace oneliner AST */\npublic class OnelinerValidator {\n\n  /**\n   * Validate a parsed oneliner AST\n   *\n   * @throws OnelinerException if validation fails\n   */\n  public static void validate(OnelinerNode node, String input) {\n    ProbeClause probe = node.probe;\n\n    // Validate probe spec\n    validateProbeSpec(probe.probeSpec, input);\n\n    // Validate filter for location\n    if (probe.filter != null) {\n      validateFilter(probe.filter, probe.probeSpec.location, input);\n    }\n\n    // Validate actions for location\n    validateActions(probe.actionBlock, probe.probeSpec.location, input);\n  }\n\n  private static void validateProbeSpec(ProbeSpec spec, String input) {\n    // Validate class pattern is not empty\n    if (spec.classPattern == null || spec.classPattern.trim().isEmpty()) {\n      throw new OnelinerException(\"Class pattern cannot be empty\", input, 0);\n    }\n\n    // Validate method pattern is not empty\n    if (spec.methodPattern == null || spec.methodPattern.trim().isEmpty()) {\n      throw new OnelinerException(\"Method pattern cannot be empty\", input, 0);\n    }\n\n    // Validate regex patterns\n    validateRegexPattern(spec.classPattern, \"class pattern\", input);\n    validateRegexPattern(spec.methodPattern, \"method pattern\", input);\n  }\n\n  private static void validateRegexPattern(String pattern, String patternName, String input) {\n    if (pattern.startsWith(\"/\") && pattern.endsWith(\"/\")) {\n      String regex = pattern.substring(1, pattern.length() - 1);\n      try {\n        Pattern.compile(regex);\n      } catch (PatternSyntaxException e) {\n        throw new OnelinerException(\n            \"Invalid regex in \" + patternName + \": \" + e.getMessage(), input, 0);\n      }\n    }\n  }\n\n  private static void validateFilter(Filter filter, Location location, String input) {\n    if (filter.type == FilterType.DURATION) {\n      // Duration filter only valid for RETURN and ERROR locations\n      if (location != Location.RETURN && location != Location.ERROR) {\n        throw new OnelinerException(\n            \"'duration' filter requires @return or @error location (found: @\"\n                + location.name().toLowerCase()\n                + \")\",\n            input,\n            0);\n      }\n\n      // Validate duration value is positive\n      if (filter.value instanceof Integer && (Integer) filter.value <= 0) {\n        throw new OnelinerException(\"Duration value must be positive\", input, 0);\n      }\n    }\n\n    if (filter.type == FilterType.ARG_COMPARE) {\n      ArgFilter argFilter = (ArgFilter) filter;\n      // Argument index validation already done in AST construction\n      if (argFilter.argIndex < 0) {\n        throw new OnelinerException(\"Argument index must be non-negative\", input, 0);\n      }\n    }\n  }\n\n  private static void validateActions(ActionBlock actionBlock, Location location, String input) {\n    Set<String> seenActions = new HashSet<>();\n\n    for (Action action : actionBlock.actions) {\n      if (action instanceof PrintAction) {\n        validatePrintAction((PrintAction) action, location, input);\n      } else if (action instanceof CountAction) {\n        // Count action is valid for all locations\n        if (seenActions.contains(\"count\")) {\n          throw new OnelinerException(\"Duplicate 'count' action in action block\", input, 0);\n        }\n        seenActions.add(\"count\");\n      } else if (action instanceof TimeAction) {\n        // Time action requires RETURN or ERROR location\n        if (location != Location.RETURN && location != Location.ERROR) {\n          throw new OnelinerException(\n              \"'time' action requires @return or @error location (found: @\"\n                  + location.name().toLowerCase()\n                  + \")\",\n              input,\n              0);\n        }\n        if (seenActions.contains(\"time\")) {\n          throw new OnelinerException(\"Duplicate 'time' action in action block\", input, 0);\n        }\n        seenActions.add(\"time\");\n      } else if (action instanceof StackAction) {\n        StackAction stackAction = (StackAction) action;\n        // Stack depth validation already done in AST construction\n        if (stackAction.depth != null && stackAction.depth <= 0) {\n          throw new OnelinerException(\n              \"Stack depth must be positive (got: \" + stackAction.depth + \")\", input, 0);\n        }\n      }\n    }\n  }\n\n  private static void validatePrintAction(PrintAction action, Location location, String input) {\n    for (String arg : action.args) {\n      switch (arg) {\n        case \"duration\":\n          if (location != Location.RETURN && location != Location.ERROR) {\n            throw new OnelinerException(\n                \"'duration' identifier only available with @return or @error location (found: @\"\n                    + location.name().toLowerCase()\n                    + \")\",\n                input,\n                0);\n          }\n          break;\n\n        case \"return\":\n          if (location != Location.RETURN) {\n            throw new OnelinerException(\n                \"'return' identifier only available with @return location (found: @\"\n                    + location.name().toLowerCase()\n                    + \")\",\n                input,\n                0);\n          }\n          break;\n\n        case \"method\":\n        case \"args\":\n        case \"self\":\n        case \"class\":\n          // These are valid for all locations\n          break;\n\n        default:\n          throw new OnelinerException(\"Unknown print identifier: '\" + arg + \"'\", input, 0);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/test/java/org/openjdk/btrace/compiler/JfrEventsTest.java",
    "content": "package org.openjdk.btrace.compiler;\n\nimport java.io.File;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.net.URL;\nimport java.util.Map;\nimport org.junit.jupiter.api.Test;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.util.CheckClassAdapter;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.instr.BTraceProbe;\nimport org.openjdk.btrace.instr.BTraceProbeFactory;\n\nimport static org.junit.jupiter.api.Assertions.fail;\n\npublic class JfrEventsTest {\n  @Test\n  public void testCompile() throws Exception {\n    URL input = JfrEventsTest.class.getResource(\"/JfrEventsProbe.java\");\n    File inputFile = new File(input.toURI());\n    Map<String, byte[]> data =\n        new Compiler(true)\n            .compile(\n                inputFile,\n                new PrintWriter(System.err),\n                null,\n                System.getProperty(\"java.class.path\"));\n    BTraceProbeFactory factory = new BTraceProbeFactory(SharedSettings.GLOBAL);\n    for (byte[] bytes : data.values()) {\n      BTraceProbe probe = factory.createProbe(bytes);\n      verifyCode(probe.getFullBytecode());\n      verifyCode(probe.getDataHolderBytecode());\n    }\n  }\n\n  private void verifyCode(byte[] code) {\n    StringWriter sw = new StringWriter();\n    PrintWriter pw = new PrintWriter(sw);\n    CheckClassAdapter.verify(new ClassReader(code), true, pw);\n    if (sw.toString().contains(\"AnalyzerException\")) {\n      System.err.println(sw);\n      fail();\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/test/java/org/openjdk/btrace/compiler/TypeErasureTest.java",
    "content": "package org.openjdk.btrace.compiler;\n\nimport org.junit.jupiter.api.Test;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.util.CheckClassAdapter;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.instr.BTraceProbe;\nimport org.openjdk.btrace.instr.BTraceProbeFactory;\n\nimport java.io.File;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.net.URL;\nimport java.util.Map;\n\nimport static org.junit.jupiter.api.Assertions.fail;\n\npublic class TypeErasureTest {\n    @Test\n    void testTypeErasure() throws Exception {\n        URL input = TypeErasureTest.class.getResource(\"/HistoProbe.java\");\n        File inputFile = new File(input.toURI());\n        Map<String, byte[]> data =\n                new Compiler(true)\n                        .compile(\n                                inputFile,\n                                new PrintWriter(System.err),\n                                null,\n                                System.getProperty(\"java.class.path\"));\n        BTraceProbeFactory factory = new BTraceProbeFactory(SharedSettings.GLOBAL);\n        for (byte[] bytes : data.values()) {\n            BTraceProbe probe = factory.createProbe(bytes);\n            verifyCode(probe.getFullBytecode());\n            verifyCode(probe.getDataHolderBytecode());\n        }\n    }\n\n    private void verifyCode(byte[] code) {\n        StringWriter sw = new StringWriter();\n        PrintWriter pw = new PrintWriter(sw);\n        CheckClassAdapter.verify(new ClassReader(code), true, pw);\n        if (sw.toString().contains(\"AnalyzerException\")) {\n            System.err.println(sw);\n            fail();\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-compiler/src/test/java/org/openjdk/btrace/compiler/oneliner/OnelinerCodeGeneratorTest.java",
    "content": "package org.openjdk.btrace.compiler.oneliner;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerAST.OnelinerNode;\n\nclass OnelinerCodeGeneratorTest {\n\n  @Test\n  void testGenerateSimpleEntry() {\n    String input = \"javax.swing.JButton::setText @entry { print method }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"@BTrace\"));\n    assertTrue(generated.contains(\"@OnMethod(clazz=\\\"javax.swing.JButton\\\", method=\\\"setText\\\")\"));\n    assertTrue(generated.contains(\"@ProbeMethodName String method\"));\n    assertTrue(generated.contains(\"BTraceUtils.println(method)\"));\n  }\n\n  @Test\n  void testGenerateReturn() {\n    String input = \"java.util.HashMap::get @return { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"@Location(Kind.RETURN)\"));\n  }\n\n  @Test\n  void testGenerateError() {\n    String input = \"java.lang.OutOfMemoryError::<init> @error { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"@Location(Kind.ERROR)\"));\n    assertTrue(generated.contains(\"clazz=\\\"java.lang.OutOfMemoryError\\\"\"));\n    assertTrue(generated.contains(\"method=\\\"<init>\\\"\"));\n  }\n\n  @Test\n  void testGeneratePrintMultipleArgs() {\n    String input = \"Test::test @entry { print method, args }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"@ProbeMethodName String method\"));\n    assertTrue(generated.contains(\"AnyType[] args\"));\n    assertTrue(generated.contains(\"BTraceUtils.println(method + \\\" \\\" + BTraceUtils.str(args))\"));\n  }\n\n  @Test\n  void testGeneratePrintAllIdentifiers() {\n    String input = \"Test::test @return { print method, class, args, duration, return, self }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"@ProbeMethodName String method\"));\n    assertTrue(generated.contains(\"@ProbeClassName String className\"));\n    assertTrue(generated.contains(\"AnyType[] args\"));\n    assertTrue(generated.contains(\"@Duration long duration\"));\n    assertTrue(generated.contains(\"@Return AnyType returnValue\"));\n    assertTrue(generated.contains(\"@Self Object self\"));\n  }\n\n  @Test\n  void testGenerateCount() {\n    String input = \"java.util.HashMap::get @entry { count }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"private static final AtomicInteger counter\"));\n    assertTrue(generated.contains(\"BTraceUtils.incrementAndGet(counter)\"));\n    assertTrue(generated.contains(\"@OnEvent\"));\n    assertTrue(generated.contains(\"BTraceUtils.println(\\\"count: \\\" + BTraceUtils.get(counter))\"));\n  }\n\n  @Test\n  void testGenerateTime() {\n    String input = \"Test::test @return { time }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"@Duration long duration\"));\n    assertTrue(generated.contains(\"execution time\"));\n  }\n\n  @Test\n  void testGenerateStackWithoutDepth() {\n    String input = \"Test::test @entry { stack }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"BTraceUtils.jstack()\"));\n  }\n\n  @Test\n  void testGenerateStackWithDepth() {\n    String input = \"Test::test @entry { stack(10) }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"BTraceUtils.jstack(10)\"));\n  }\n\n  @Test\n  void testGenerateDurationFilterGreaterThan() {\n    String input = \"java.sql.Statement::execute @return if duration>100ms { print method }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"if (duration > 100000000L)\"));\n    assertTrue(generated.contains(\"BTraceUtils.println(method)\"));\n  }\n\n  @Test\n  void testGenerateDurationFilterGreaterThanOrEqual() {\n    String input = \"Test::test @return if duration>=50ms { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"if (duration >= 50000000L)\"));\n  }\n\n  @Test\n  void testGenerateDurationFilterLessThan() {\n    String input = \"Test::test @return if duration<10ms { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"if (duration < 10000000L)\"));\n  }\n\n  @Test\n  void testGenerateArgFilterStringEquals() {\n    String input = \"Test::test @entry if args[0]==\\\"test\\\" { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"args.length > 0\"));\n    assertTrue(\n        generated.contains(\"BTraceUtils.compare(\\\"test\\\", BTraceUtils.str(args[0]))\"));\n  }\n\n  @Test\n  void testGenerateArgFilterStringNotEquals() {\n    String input = \"Test::test @entry if args[0]!=\\\"foo\\\" { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(\n        generated.contains(\"!BTraceUtils.compare(\\\"foo\\\", BTraceUtils.str(args[0]))\"));\n  }\n\n  @Test\n  void testGenerateArgFilterNumberGreaterThan() {\n    String input = \"Test::test @entry if args[1]>100 { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"args.length > 1\"));\n    assertTrue(generated.contains(\"((Number)args[1]).longValue() > 100L\"));\n  }\n\n  @Test\n  void testGenerateMultipleActions() {\n    String input = \"Test::test @entry { print method, count, stack }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"BTraceUtils.println(method)\"));\n    assertTrue(generated.contains(\"BTraceUtils.incrementAndGet(counter)\"));\n    assertTrue(generated.contains(\"BTraceUtils.jstack()\"));\n    assertTrue(generated.contains(\"@OnEvent\"));\n  }\n\n  @Test\n  void testGenerateRegexPattern() {\n    String input = \"/com\\\\.myapp\\\\..*/::execute @entry { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"clazz=\\\"/com\\\\\\\\.myapp\\\\\\\\..*/\")); // Escaping in generated code\n  }\n\n  @Test\n  void testClassNameIsUnique() throws InterruptedException {\n    String input = \"Test::test @entry { print }\";\n    OnelinerNode ast1 = OnelinerParser.parse(input);\n    String generated1 = OnelinerCodeGenerator.generate(ast1);\n\n    OnelinerNode ast2 = OnelinerParser.parse(input);\n    String generated2 = OnelinerCodeGenerator.generate(ast2);\n\n    // Class name is fixed (BTraceOneliner) - uniqueness not required since\n    // each oneliner gets its own temp file and class loader context\n    assertTrue(generated1.contains(\"class BTraceOneliner\"));\n    assertTrue(generated2.contains(\"class BTraceOneliner\"));\n  }\n\n  @Test\n  void testGeneratedCodeHasCorrectPackage() {\n    String input = \"Test::test @entry { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"package org.openjdk.btrace.generated;\"));\n  }\n\n  @Test\n  void testGeneratedCodeHasRequiredImports() {\n    String input = \"Test::test @entry { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n    String generated = OnelinerCodeGenerator.generate(ast);\n\n    assertTrue(generated.contains(\"import org.openjdk.btrace.core.BTraceUtils;\"));\n    assertTrue(generated.contains(\"import org.openjdk.btrace.core.annotations.*;\"));\n    assertTrue(generated.contains(\"import org.openjdk.btrace.core.types.AnyType;\"));\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/test/java/org/openjdk/btrace/compiler/oneliner/OnelinerIntegrationTest.java",
    "content": "package org.openjdk.btrace.compiler.oneliner;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Map;\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.compiler.Compiler;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerAST.OnelinerNode;\n\n/**\n * Integration tests that verify oneliner-generated code compiles with the real BTrace compiler.\n */\nclass OnelinerIntegrationTest {\n\n  @Test\n  void testCompileSimpleEntry() {\n    String oneliner = \"javax.swing.JButton::setText @entry { print method }\";\n    byte[] bytecode = compileOneliner(oneliner);\n\n    assertNotNull(bytecode);\n    assertTrue(bytecode.length > 0);\n  }\n\n  @Test\n  void testCompileReturnWithFilter() {\n    String oneliner = \"java.sql.Statement::execute @return if duration>100ms { print method, duration }\";\n    byte[] bytecode = compileOneliner(oneliner);\n\n    assertNotNull(bytecode);\n    assertTrue(bytecode.length > 0);\n  }\n\n  @Test\n  void testCompileCount() {\n    String oneliner = \"java.util.HashMap::get @entry { count }\";\n    byte[] bytecode = compileOneliner(oneliner);\n\n    assertNotNull(bytecode);\n    assertTrue(bytecode.length > 0);\n  }\n\n  @Test\n  void testCompileStack() {\n    String oneliner = \"java.lang.OutOfMemoryError::<init> @return { stack(10) }\";\n    byte[] bytecode = compileOneliner(oneliner);\n\n    assertNotNull(bytecode);\n    assertTrue(bytecode.length > 0);\n  }\n\n  @Test\n  void testCompileMultipleActions() {\n    String oneliner = \"Test::test @entry { print method, count, stack }\";\n    byte[] bytecode = compileOneliner(oneliner);\n\n    assertNotNull(bytecode);\n    assertTrue(bytecode.length > 0);\n  }\n\n  @Test\n  void testCompileArgFilter() {\n    String oneliner = \"Test::test @entry if args[0]==\\\"test\\\" { print }\";\n    byte[] bytecode = compileOneliner(oneliner);\n\n    assertNotNull(bytecode);\n    assertTrue(bytecode.length > 0);\n  }\n\n  @Test\n  void testCompileRegexPattern() {\n    String oneliner = \"/com\\\\.myapp\\\\..*/::execute @entry { print }\";\n    byte[] bytecode = compileOneliner(oneliner);\n\n    assertNotNull(bytecode);\n    assertTrue(bytecode.length > 0);\n  }\n\n  @Test\n  void testCompileError() {\n    String oneliner = \"java.lang.Exception::<init> @error { print self }\";\n    byte[] bytecode = compileOneliner(oneliner);\n\n    assertNotNull(bytecode);\n    assertTrue(bytecode.length > 0);\n  }\n\n  @Test\n  void testCompileTime() {\n    String oneliner = \"Test::test @return { time }\";\n    byte[] bytecode = compileOneliner(oneliner);\n\n    assertNotNull(bytecode);\n    assertTrue(bytecode.length > 0);\n  }\n\n  @Test\n  void testCompilePrintAllIdentifiers() {\n    String oneliner = \"Test::test @return { print method, class, args, duration, return, self }\";\n    byte[] bytecode = compileOneliner(oneliner);\n\n    assertNotNull(bytecode);\n    assertTrue(bytecode.length > 0);\n  }\n\n  /**\n   * Helper method to compile a oneliner end-to-end: parse -> validate -> generate -> compile\n   */\n  private byte[] compileOneliner(String oneliner) {\n    try {\n      // Parse\n      OnelinerNode ast = OnelinerParser.parse(oneliner);\n\n      // Validate\n      OnelinerValidator.validate(ast, oneliner);\n\n      // Generate Java source\n      String javaSource = OnelinerCodeGenerator.generate(ast);\n\n      // Print generated source for debugging (if test fails)\n      if (System.getProperty(\"btrace.test.debug\") != null) {\n        System.out.println(\"=== Generated Java for: \" + oneliner + \" ===\");\n        System.out.println(javaSource);\n        System.out.println(\"=== End Generated Java ===\\n\");\n      }\n\n      // Compile with real BTrace compiler\n      Compiler compiler = new Compiler();\n      StringWriter errorWriter = new StringWriter();\n      Map<String, byte[]> compiled =\n          compiler.compile(\n              \"BTraceOneliner.java\",\n              javaSource,\n              new PrintWriter(errorWriter),\n              \".\",\n              System.getProperty(\"java.class.path\"));\n\n      // Check for compilation errors\n      String errors = errorWriter.toString();\n      if (!errors.isEmpty()) {\n        fail(\"Compilation failed for oneliner: \" + oneliner + \"\\nErrors:\\n\" + errors);\n      }\n\n      assertNotNull(compiled, \"Compiler returned null\");\n      assertFalse(compiled.isEmpty(), \"No classes were compiled\");\n\n      // Return the first compiled class\n      return compiled.values().iterator().next();\n    } catch (Exception e) {\n      fail(\"Failed to compile oneliner: \" + oneliner + \"\\nException: \" + e.getMessage(), e);\n      return null;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/test/java/org/openjdk/btrace/compiler/oneliner/OnelinerParserTest.java",
    "content": "package org.openjdk.btrace.compiler.oneliner;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.compiler.oneliner.OnelinerAST.*;\n\nclass OnelinerParserTest {\n\n  @Test\n  void testSimpleEntryProbe() {\n    String input = \"javax.swing.*::setText @entry { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    assertNotNull(ast);\n    assertEquals(\"javax.swing.*\", ast.probe.probeSpec.classPattern);\n    assertEquals(\"setText\", ast.probe.probeSpec.methodPattern);\n    assertEquals(Location.ENTRY, ast.probe.probeSpec.location);\n    assertNull(ast.probe.filter);\n    assertEquals(1, ast.probe.actionBlock.actions.size());\n    assertTrue(ast.probe.actionBlock.actions.get(0) instanceof PrintAction);\n  }\n\n  @Test\n  void testReturnProbe() {\n    String input = \"java.util.HashMap::get @return { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    assertEquals(Location.RETURN, ast.probe.probeSpec.location);\n  }\n\n  @Test\n  void testErrorProbe() {\n    String input = \"java.lang.OutOfMemoryError::<init> @error { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    assertEquals(\"java.lang.OutOfMemoryError\", ast.probe.probeSpec.classPattern);\n    assertEquals(\"<init>\", ast.probe.probeSpec.methodPattern);\n    assertEquals(Location.ERROR, ast.probe.probeSpec.location);\n  }\n\n  @Test\n  void testRegexPattern() {\n    String input = \"/com\\\\.myapp\\\\..*/::execute @entry { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    assertEquals(\"/com\\\\.myapp\\\\..*/\", ast.probe.probeSpec.classPattern);\n  }\n\n  @Test\n  void testMethodRegexPattern() {\n    String input = \"java.sql.Statement::/execute.*/ @entry { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    assertEquals(\"java.sql.Statement\", ast.probe.probeSpec.classPattern);\n    assertEquals(\"/execute.*/\", ast.probe.probeSpec.methodPattern);\n  }\n\n  @Test\n  void testPrintWithArguments() {\n    String input = \"javax.swing.*::* @entry { print method, args }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    PrintAction printAction = (PrintAction) ast.probe.actionBlock.actions.get(0);\n    assertEquals(2, printAction.args.size());\n    assertEquals(\"method\", printAction.args.get(0));\n    assertEquals(\"args\", printAction.args.get(1));\n  }\n\n  @Test\n  void testPrintAllIdentifiers() {\n    String input = \"Test::test @return { print method, args, duration, return, self, class }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    PrintAction printAction = (PrintAction) ast.probe.actionBlock.actions.get(0);\n    assertEquals(6, printAction.args.size());\n    assertEquals(\"method\", printAction.args.get(0));\n    assertEquals(\"args\", printAction.args.get(1));\n    assertEquals(\"duration\", printAction.args.get(2));\n    assertEquals(\"return\", printAction.args.get(3));\n    assertEquals(\"self\", printAction.args.get(4));\n    assertEquals(\"class\", printAction.args.get(5));\n  }\n\n  @Test\n  void testCountAction() {\n    String input = \"java.util.HashMap::get @entry { count }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    assertTrue(ast.probe.actionBlock.actions.get(0) instanceof CountAction);\n  }\n\n  @Test\n  void testTimeAction() {\n    String input = \"java.sql.Statement::execute @return { time }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    assertTrue(ast.probe.actionBlock.actions.get(0) instanceof TimeAction);\n  }\n\n  @Test\n  void testStackAction() {\n    String input = \"Test::test @entry { stack }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    StackAction stackAction = (StackAction) ast.probe.actionBlock.actions.get(0);\n    assertNull(stackAction.depth);\n  }\n\n  @Test\n  void testStackActionWithDepth() {\n    String input = \"Test::test @entry { stack(10) }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    StackAction stackAction = (StackAction) ast.probe.actionBlock.actions.get(0);\n    assertEquals(10, stackAction.depth);\n  }\n\n  @Test\n  void testMultipleActions() {\n    String input = \"Test::test @entry { print method, count, stack }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    assertEquals(3, ast.probe.actionBlock.actions.size());\n    assertTrue(ast.probe.actionBlock.actions.get(0) instanceof PrintAction);\n    assertTrue(ast.probe.actionBlock.actions.get(1) instanceof CountAction);\n    assertTrue(ast.probe.actionBlock.actions.get(2) instanceof StackAction);\n  }\n\n  @Test\n  void testDurationFilterGreaterThan() {\n    String input = \"java.sql.Statement::execute @return if duration>100ms { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    assertNotNull(ast.probe.filter);\n    assertEquals(FilterType.DURATION, ast.probe.filter.type);\n    assertEquals(Comparator.GT, ast.probe.filter.comparator);\n    assertEquals(100, ast.probe.filter.value);\n  }\n\n  @Test\n  void testDurationFilterGreaterThanOrEqual() {\n    String input = \"Test::test @return if duration>=50ms { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    assertEquals(Comparator.GTE, ast.probe.filter.comparator);\n    assertEquals(50, ast.probe.filter.value);\n  }\n\n  @Test\n  void testArgFilterStringEquals() {\n    String input = \"Test::test @entry if args[0]==\\\"test\\\" { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    ArgFilter argFilter = (ArgFilter) ast.probe.filter;\n    assertEquals(FilterType.ARG_COMPARE, argFilter.type);\n    assertEquals(0, argFilter.argIndex);\n    assertEquals(Comparator.EQ, argFilter.comparator);\n    assertEquals(\"test\", argFilter.value);\n  }\n\n  @Test\n  void testArgFilterNumberGreaterThan() {\n    String input = \"Test::test @entry if args[1]>100 { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    ArgFilter argFilter = (ArgFilter) ast.probe.filter;\n    assertEquals(1, argFilter.argIndex);\n    assertEquals(Comparator.GT, argFilter.comparator);\n    assertEquals(100, argFilter.value);\n  }\n\n  @Test\n  void testArgFilterNotEquals() {\n    String input = \"Test::test @entry if args[0]!=\\\"foo\\\" { print }\";\n    OnelinerNode ast = OnelinerParser.parse(input);\n\n    ArgFilter argFilter = (ArgFilter) ast.probe.filter;\n    assertEquals(Comparator.NEQ, argFilter.comparator);\n  }\n\n  @Test\n  void testErrorMissingDoubleColon() {\n    String input = \"javax.swing.* setText @entry { print }\";\n    assertThrows(OnelinerException.class, () -> OnelinerParser.parse(input));\n  }\n\n  @Test\n  void testErrorMissingAt() {\n    String input = \"javax.swing.*::setText entry { print }\";\n    assertThrows(OnelinerException.class, () -> OnelinerParser.parse(input));\n  }\n\n  @Test\n  void testErrorMissingActionBlock() {\n    String input = \"javax.swing.*::setText @entry\";\n    assertThrows(OnelinerException.class, () -> OnelinerParser.parse(input));\n  }\n\n  @Test\n  void testErrorMissingClosingBrace() {\n    String input = \"javax.swing.*::setText @entry { print\";\n    assertThrows(OnelinerException.class, () -> OnelinerParser.parse(input));\n  }\n\n  @Test\n  void testErrorInvalidLocation() {\n    String input = \"javax.swing.*::setText @invalid { print }\";\n    assertThrows(OnelinerException.class, () -> OnelinerParser.parse(input));\n  }\n\n  @Test\n  void testErrorInvalidAction() {\n    String input = \"javax.swing.*::setText @entry { invalid }\";\n    assertThrows(OnelinerException.class, () -> OnelinerParser.parse(input));\n  }\n\n  @Test\n  void testErrorEmptyActionBlock() {\n    String input = \"javax.swing.*::setText @entry { }\";\n    assertThrows(OnelinerException.class, () -> OnelinerParser.parse(input));\n  }\n}\n"
  },
  {
    "path": "btrace-compiler/src/test/resources/HistoProbe.java",
    "content": "package test;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\nimport org.openjdk.btrace.core.annotations.*;\n\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n@BTrace public class HistoProbe {\n    private static Map<String, AtomicInteger> histo = newHashMap();\n    @OnMethod(clazz = \"javax.swing.JComponent\", method = \"<init>\")\n    public static void onMethod(@Self Object obj) {\n        String cn = name(classOf(obj));\n        AtomicInteger ai = get((Map<String, AtomicInteger>)histo, cn);\n        if (ai == null) {\n            ai = newAtomicInteger(1);\n            put(histo, cn, ai);\n        } else {\n            incrementAndGet(ai);\t// WORKS if commented out\n        }\n    }\n\n    @OnTimer(1000)\n    public static void print() {\n        printNumberMap(\"Component Histogram\", histo);\n    }\n}"
  },
  {
    "path": "btrace-compiler/src/test/resources/JfrEventsProbe.java",
    "content": "package test;\n\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\nimport static org.openjdk.btrace.core.BTraceUtils.Jfr.*;\n\n@BTrace public class JfrEventsProbe {\n    @Event(\n        name = \"CustomEvent\",\n        label = \"Custom Event\",\n        fields = {\n            @Event.Field(type = Event.FieldType.INT, name = \"a\"),\n            @Event.Field(type = Event.FieldType.STRING, name = \"b\")\n        }\n    )\n    private static JfrEvent.Factory customEventFactory;\n\n    @OnMethod(clazz = \"/.*/\", method = \"/.*/\")\n    public static void onMethod() {\n        JfrEvent event = prepareEvent(customEventFactory);\n        setEventField(event, \"a\", 10);\n        setEventField(event, \"b\", \"hello\");\n        commit(event);\n    }\n\n    @PeriodicEvent(name = \"PeriodicEvent\", fields = @Event.Field(type = Event.FieldType.INT, name = \"cnt\", kind = @Event.Field.Kind(name = Event.FieldKind.TIMESTAMP)), period = \"1 s\")\n    public static void onPeriod(JfrEvent event) {\n        if (shouldCommit(event)) {\n            setEventField(event, \"cnt\", 1);\n            commit(event);\n        }\n    }\n\n}"
  },
  {
    "path": "btrace-compiler/src/test/resources/MetricsExtensionProbe.java",
    "content": "package resources;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Injected;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.metrics.MetricsService;\nimport org.openjdk.btrace.metrics.histogram.HistogramConfig;\nimport org.openjdk.btrace.metrics.histogram.HistogramMetric;\nimport org.openjdk.btrace.metrics.histogram.HistogramSnapshot;\nimport org.openjdk.btrace.metrics.stats.StatsMetric;\nimport org.openjdk.btrace.metrics.stats.StatsSnapshot;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * Test probe that uses the metrics extension to verify that:\n * 1. @Injected service fields are recognized\n * 2. Methods on service return types (HistogramMetric, StatsMetric) are allowed\n * 3. Methods on snapshot objects (HistogramSnapshot, StatsSnapshot) are allowed\n */\n@BTrace\npublic class MetricsExtensionProbe {\n\n    @Injected\n    private static MetricsService metrics;\n\n    private static HistogramMetric histogram;\n    private static StatsMetric stats;\n\n    @OnMethod(clazz = \"java.lang.String\", method = \"length\", location = @Location(Kind.RETURN))\n    public static void onStringLength(@Duration long durationNanos) {\n        // Initialize metrics on first call\n        if (histogram == null) {\n            histogram = metrics.histogramMicros(\"string.length\");\n            stats = metrics.stats(\"string.length.stats\");\n        }\n\n        // Record duration - these calls should be allowed by the verifier\n        long durationMicros = durationNanos / 1000;\n        histogram.record(durationMicros);\n        stats.record(durationMicros);\n\n        // Get snapshots - these calls should be allowed\n        HistogramSnapshot h = histogram.snapshot();\n        StatsSnapshot s = stats.snapshot();\n\n        // Call methods on snapshots - these should also be allowed\n        println(\"Count: \" + s.count());\n        println(\"Mean: \" + s.mean());\n        println(\"P99: \" + h.p99());\n    }\n}\n"
  },
  {
    "path": "btrace-core/JMH_BENCHMARKS.md",
    "content": "# JMH Benchmarks for Binary Protocol v2\n\n## Overview\n\nThis document describes how to run the JMH (Java Microbenchmark Harness) benchmarks for the binary protocol v2 implementation.\n\nThe benchmarks compare the performance of the new binary protocol against Java serialization across multiple command types and data sizes.\n\n## Running Benchmarks\n\n### Run All Benchmarks\n\n```bash\n./gradlew :btrace-core:jmh\n```\n\nThis will run all benchmarks with default settings:\n- 3 warmup iterations\n- 5 measurement iterations\n- 2 forks\n- 1 thread\n- Both throughput and average time modes\n\n### Filter Benchmarks\n\nUse the `jmhInclude` property to filter which benchmarks to run:\n\n```bash\n# Run only serialization benchmarks\n./gradlew :btrace-core:jmh -PjmhInclude=\".*Serialize\"\n\n# Run only deserialization benchmarks\n./gradlew :btrace-core:jmh -PjmhInclude=\".*Deserialize\"\n\n# Run only round-trip benchmarks\n./gradlew :btrace-core:jmh -PjmhInclude=\".*RoundTrip\"\n\n# Run benchmarks for specific command type\n./gradlew :btrace-core:jmh -PjmhInclude=\".*InstrumentCommand.*\"\n\n# Run benchmarks for specific data size\n./gradlew :btrace-core:jmh -PjmhInclude=\".*small.*\"\n```\n\n## Benchmark Structure\n\n### Command Types Tested\n\nThe benchmarks test the following command types:\n1. **InstrumentCommand** - Bytecode instrumentation with byte arrays\n2. **MessageCommand** - Text messages\n3. **ErrorCommand** - Error reporting\n4. **EventCommand** - Event notifications\n5. **StatusCommand** - Status updates\n6. **NumberMapDataCommand** - Maps with numeric values\n7. **StringMapDataCommand** - Maps with string values\n8. **NumberDataCommand** - Single numeric values\n9. **GridDataCommand** - Tabular data\n10. **ExitCommand** - Exit signals\n\n### Data Sizes\n\nEach command type is tested with three data sizes:\n- **small** - Minimal data (e.g., 50 chars, 100 bytes, 5 entries)\n- **medium** - Moderate data (e.g., 500 chars, 1KB, 50 entries)\n- **large** - Large data (e.g., 5000 chars, 10KB, 500 entries)\n\n### Benchmark Methods\n\nEach command type/size combination is tested with:\n- `binarySerialize` - Serialize using binary protocol\n- `binaryDeserialize` - Deserialize using binary protocol\n- `javaSerialize` - Serialize using Java serialization\n- `javaDeserialize` - Deserialize using Java serialization\n- `binaryRoundTrip` - Full round-trip with binary protocol\n- `javaRoundTrip` - Full round-trip with Java serialization\n\n## Interpreting Results\n\n### Throughput (ops/us)\nHigher is better. Shows how many operations per microsecond.\n\n### Average Time (us/op)\nLower is better. Shows microseconds per operation.\n\n### Example Output\n\n```\nBenchmark                                    (commandType)  (dataSize)  Mode  Cnt   Score   Error   Units\nBinaryProtocolBenchmark.binarySerialize     MessageCommand       small  avgt   10   5.234 ± 0.123   us/op\nBinaryProtocolBenchmark.javaSerialize       MessageCommand       small  avgt   10  12.456 ± 0.234   us/op\n```\n\nThis shows binary serialization is ~2.4x faster than Java serialization for small messages.\n\n## Expected Performance Improvements\n\nBased on architecture design goals, the binary protocol should deliver:\n\n| Metric | Target Improvement |\n|--------|-------------------|\n| Serialization Speed | 3-6x faster |\n| Deserialization Speed | 3-6x faster |\n| Wire Size | 2-5x smaller |\n| Memory Allocation | Significantly reduced |\n\nWith compression enabled (for messages >1KB):\n- Wire size improvements can be 10-100x for highly compressible data\n- Speed may be slower due to compression overhead\n\n## Customizing Benchmarks\n\nEdit `btrace-core/build.gradle` to change JMH settings:\n\n```gradle\njmh {\n    warmupIterations = 3      // Number of warmup iterations\n    iterations = 5            // Number of measurement iterations\n    fork = 2                  // Number of forked JVM processes\n    threads = 1               // Number of worker threads\n    timeUnit = 'ms'          // Time unit for results\n    benchmarkMode = ['avgt', 'thrpt']  // Benchmark modes\n}\n```\n\n## Benchmark Output Location\n\nJMH results are written to:\n- Console output during execution\n- `btrace-core/build/reports/jmh/` (if configured)\n\n## Best Practices\n\n1. **Close other applications** - Minimize system noise\n2. **Run multiple times** - JMH forks handle this automatically\n3. **Check for GC** - Look for GC pauses in output\n4. **Compare same system** - Run before/after on same hardware\n5. **Use realistic data** - Adjust data sizes to match production\n\n## Advanced Usage\n\n### Custom JMH Options\n\nPass JMH options directly:\n\n```bash\n./gradlew :btrace-core:jmh -PjmhInclude=\".*Serialize\" \\\n  --args=\"-prof gc -prof stack -rf json -rff results.json\"\n```\n\nCommon profilers:\n- `-prof gc` - GC profiling\n- `-prof stack` - Stack traces\n- `-prof perfnorm` - Normalized perf events\n\n### Output Formats\n\n- `-rf csv` - CSV output\n- `-rf json` - JSON output\n- `-rf text` - Text output (default)\n\n## Troubleshooting\n\n### Out of Memory\nIncrease heap size:\n```bash\n./gradlew :btrace-core:jmh -Dorg.gradle.jvmargs=\"-Xmx4g\"\n```\n\n### Benchmarks Take Too Long\nReduce iterations:\n```gradle\njmh {\n    warmupIterations = 1\n    iterations = 2\n    fork = 1\n}\n```\n\n### Need More Detail\nEnable JMH verbose output:\n```bash\n./gradlew :btrace-core:jmh --args=\"-v EXTRA\"\n```\n"
  },
  {
    "path": "btrace-core/build.gradle",
    "content": "import org.apache.tools.ant.filters.*\n\nbuildscript { scriptHandler ->\n    apply from: rootProject.file('buildSrc/shared.gradle'), to: scriptHandler\n}\n\nplugins {\n    alias(libs.plugins.jmh)\n    id 'jacoco'\n}\n\ndependencies {\n    implementation libs.slf4j\n    implementation libs.slf4j.simple\n    implementation libs.jctools\n    implementation libs.asm\n    implementation libs.asm.util\n\n    jmh libs.jmh\n    jmh libs.jmh.annprocess\n}\n\njmh {\n    warmupIterations = 3\n    iterations = 5\n    fork = 2\n    threads = 1\n    timeUnit = 'ms'\n    def jmhIncludeProp = project.findProperty('jmhInclude')\n    includes = jmhIncludeProp ? [jmhIncludeProp] : ['.*BinaryProtocol.*']\n    benchmarkMode = ['avgt', 'thrpt']\n}\n\nprocessResources {\n    filter ReplaceTokens, tokens: [\n        \"btrace.version\": project.version,\n        \"hash\"          : getGitCommit()\n    ]\n}\n\njacoco {\n    toolVersion = \"0.8.14\"\n}\n\njacocoTestReport {\n    dependsOn test\n    reports {\n        xml.required = true\n        html.required = true\n        csv.required = false\n    }\n\n    // Focus on v2 protocol package\n    afterEvaluate {\n        classDirectories.setFrom(files(classDirectories.files.collect {\n            fileTree(dir: it, include: [\n                '**/org/openjdk/btrace/core/comm/**/*.class'\n            ])\n        }))\n    }\n}\n\ntest {\n    finalizedBy jacocoTestReport\n}\n"
  },
  {
    "path": "btrace-core/src/jmh/java/org/openjdk/btrace/core/comm/v2/BinaryProtocolBenchmark.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.ErrorCommand;\nimport org.openjdk.btrace.core.comm.EventCommand;\nimport org.openjdk.btrace.core.comm.ExitCommand;\nimport org.openjdk.btrace.core.comm.GridDataCommand;\nimport org.openjdk.btrace.core.comm.InstrumentCommand;\nimport org.openjdk.btrace.core.comm.MessageCommand;\nimport org.openjdk.btrace.core.comm.NumberDataCommand;\nimport org.openjdk.btrace.core.comm.NumberMapDataCommand;\nimport org.openjdk.btrace.core.comm.StatusCommand;\nimport org.openjdk.btrace.core.comm.StringMapDataCommand;\nimport org.openjdk.btrace.core.comm.WireIO;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Measurement;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Param;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.Warmup;\n\n/**\n * JMH benchmarks for the binary protocol vs Java serialization.\n * Tests serialization and deserialization performance across all command types.\n */\n@BenchmarkMode({Mode.Throughput, Mode.AverageTime})\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)\n@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)\n@Fork(2)\n@State(Scope.Benchmark)\npublic class BinaryProtocolBenchmark {\n\n    @Param({\"InstrumentCommand\", \"MessageCommand\", \"ErrorCommand\", \"EventCommand\",\n            \"StatusCommand\", \"NumberMapDataCommand\", \"StringMapDataCommand\",\n            \"NumberDataCommand\", \"GridDataCommand\", \"ExitCommand\"})\n    private String commandType;\n\n    @Param({\"small\", \"medium\", \"large\"})\n    private String dataSize;\n\n    private BinaryCommand binaryCommand;\n    private Command javaCommand;\n\n    @Setup\n    public void setup() {\n        switch (commandType) {\n            case \"InstrumentCommand\":\n                byte[] code = createByteArray(dataSize);\n                String[] args = {\"arg1\", \"arg2\", \"arg3\"};\n                binaryCommand = new BinaryInstrumentCommand(code, args);\n                javaCommand = new InstrumentCommand(code, args);\n                break;\n\n            case \"MessageCommand\":\n                String message = createString(dataSize);\n                binaryCommand = new BinaryMessageCommand(message, false);\n                javaCommand = new MessageCommand(message);\n                break;\n\n            case \"ErrorCommand\":\n                Throwable cause = new RuntimeException(createString(dataSize));\n                binaryCommand = new BinaryErrorCommand(cause.getClass().getName(), cause.getMessage(), null);\n                javaCommand = new ErrorCommand(cause);\n                break;\n\n            case \"EventCommand\":\n                String eventName = \"test.event.\" + createString(dataSize);\n                binaryCommand = new BinaryEventCommand(eventName);\n                javaCommand = new EventCommand(eventName);\n                break;\n\n            case \"StatusCommand\":\n                binaryCommand = new BinaryStatusCommand(1, true);\n                javaCommand = new StatusCommand(1);\n                break;\n\n            case \"NumberMapDataCommand\":\n                Map<String, Number> numberMap = createNumberMap(dataSize);\n                binaryCommand = new BinaryNumberMapDataCommand(\"test\", numberMap);\n                javaCommand = new NumberMapDataCommand(\"test\", numberMap);\n                break;\n\n            case \"StringMapDataCommand\":\n                Map<String, String> stringMap = createStringMap(dataSize);\n                binaryCommand = new BinaryStringMapDataCommand(\"test\", stringMap);\n                javaCommand = new StringMapDataCommand(\"test\", stringMap);\n                break;\n\n            case \"NumberDataCommand\":\n                binaryCommand = new BinaryNumberDataCommand(\"test\", 42);\n                javaCommand = new NumberDataCommand(\"test\", 42);\n                break;\n\n            case \"GridDataCommand\":\n                List<Object[]> gridData = createGridData(dataSize);\n                List<String> columnNames = new ArrayList<>();\n                columnNames.add(\"Name\");\n                columnNames.add(\"ID\");\n                columnNames.add(\"Value\");\n                binaryCommand = new BinaryGridDataCommand(\"test\", columnNames, gridData);\n                javaCommand = new GridDataCommand(\"test\", gridData);\n                break;\n\n            case \"ExitCommand\":\n                binaryCommand = new BinaryExitCommand(0);\n                javaCommand = new ExitCommand(0);\n                break;\n\n            default:\n                throw new IllegalArgumentException(\"Unknown command type: \" + commandType);\n        }\n    }\n\n    @Benchmark\n    public byte[] binarySerialize() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryWireIO.write(baos, binaryCommand);\n        return baos.toByteArray();\n    }\n\n    @Benchmark\n    public BinaryCommand binaryDeserialize() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryWireIO.write(baos, binaryCommand);\n        byte[] data = baos.toByteArray();\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(data);\n        return BinaryWireIO.read(bais);\n    }\n\n    @Benchmark\n    public byte[] javaSerialize() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        ObjectOutputStream oos = new ObjectOutputStream(baos);\n        WireIO.write(oos, javaCommand);\n        oos.close();\n        return baos.toByteArray();\n    }\n\n    @Benchmark\n    public Command javaDeserialize() throws IOException, ClassNotFoundException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        ObjectOutputStream oos = new ObjectOutputStream(baos);\n        WireIO.write(oos, javaCommand);\n        oos.close();\n        byte[] data = baos.toByteArray();\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(data);\n        ObjectInputStream ois = new ObjectInputStream(bais);\n        Command cmd = WireIO.read(ois);\n        ois.close();\n        return cmd;\n    }\n\n    @Benchmark\n    public byte[] binaryRoundTrip() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryWireIO.write(baos, binaryCommand);\n        byte[] serialized = baos.toByteArray();\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(serialized);\n        BinaryCommand deserialized = BinaryWireIO.read(bais);\n\n        ByteArrayOutputStream baos2 = new ByteArrayOutputStream();\n        BinaryWireIO.write(baos2, deserialized);\n        return baos2.toByteArray();\n    }\n\n    @Benchmark\n    public byte[] javaRoundTrip() throws IOException, ClassNotFoundException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        ObjectOutputStream oos = new ObjectOutputStream(baos);\n        WireIO.write(oos, javaCommand);\n        oos.close();\n        byte[] serialized = baos.toByteArray();\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(serialized);\n        ObjectInputStream ois = new ObjectInputStream(bais);\n        Command deserialized = WireIO.read(ois);\n        ois.close();\n\n        ByteArrayOutputStream baos2 = new ByteArrayOutputStream();\n        ObjectOutputStream oos2 = new ObjectOutputStream(baos2);\n        WireIO.write(oos2, deserialized);\n        oos2.close();\n        return baos2.toByteArray();\n    }\n\n    private byte[] createByteArray(String size) {\n        int length;\n        switch (size) {\n            case \"small\":\n                length = 100;\n                break;\n            case \"medium\":\n                length = 1000;\n                break;\n            case \"large\":\n                length = 10000;\n                break;\n            default:\n                length = 100;\n        }\n        byte[] data = new byte[length];\n        for (int i = 0; i < length; i++) {\n            data[i] = (byte) (i % 256);\n        }\n        return data;\n    }\n\n    private String createString(String size) {\n        int length;\n        switch (size) {\n            case \"small\":\n                length = 50;\n                break;\n            case \"medium\":\n                length = 500;\n                break;\n            case \"large\":\n                length = 5000;\n                break;\n            default:\n                length = 50;\n        }\n        StringBuilder sb = new StringBuilder(length);\n        for (int i = 0; i < length; i++) {\n            sb.append((char) ('A' + (i % 26)));\n        }\n        return sb.toString();\n    }\n\n    private Map<String, Number> createNumberMap(String size) {\n        int entries;\n        switch (size) {\n            case \"small\":\n                entries = 5;\n                break;\n            case \"medium\":\n                entries = 50;\n                break;\n            case \"large\":\n                entries = 500;\n                break;\n            default:\n                entries = 5;\n        }\n        Map<String, Number> map = new HashMap<>();\n        for (int i = 0; i < entries; i++) {\n            map.put(\"key\" + i, i * 1.5);\n        }\n        return map;\n    }\n\n    private Map<String, String> createStringMap(String size) {\n        int entries;\n        switch (size) {\n            case \"small\":\n                entries = 5;\n                break;\n            case \"medium\":\n                entries = 50;\n                break;\n            case \"large\":\n                entries = 500;\n                break;\n            default:\n                entries = 5;\n        }\n        Map<String, String> map = new HashMap<>();\n        for (int i = 0; i < entries; i++) {\n            map.put(\"key\" + i, \"value\" + i);\n        }\n        return map;\n    }\n\n    private List<Object[]> createGridData(String size) {\n        int rows;\n        switch (size) {\n            case \"small\":\n                rows = 5;\n                break;\n            case \"medium\":\n                rows = 50;\n                break;\n            case \"large\":\n                rows = 500;\n                break;\n            default:\n                rows = 5;\n        }\n\n        List<Object[]> data = new ArrayList<>(rows);\n        for (int i = 0; i < rows; i++) {\n            Object[] row = new Object[3];\n            row[0] = \"row\" + i;\n            row[1] = i;\n            row[2] = i * 1.5;\n            data.add(row);\n        }\n\n        return data;\n    }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/Args.java",
    "content": "package org.openjdk.btrace.core;\n\npublic final class Args {\n  public static final String SYSTEM_CLASS_PATH = \"systemClassPath\";\n  public static final String BOOT_CLASS_PATH = \"bootClassPath\";\n  public static final String AGENT_JAR = \"agentJar\";\n  public static final String CONFIG = \"config\";\n  public static final String SCRIPT = \"script\";\n  public static final String SCRIPT_DIR = \"scriptdir\";\n  public static final String STARTUP_RETRANSFORM = \"startupRetransform\";\n  public static final String DUMP_DIR = \"dumpDir\";\n  public static final String DUMP_CLASSES = \"dumpClasses\";\n  public static final String CMD_QUEUE_LIMIT = \"cmdQueueLimit\";\n  public static final String TRACK_RETRANSFORMS = \"trackRetransforms\";\n  public static final String SCRIPT_OUTPUT_FILE = \"scriptOutputFile\";\n  public static final String SCRIPT_OUTPUT_DIR = \"scriptOutputDir\";\n  public static final String FILE_ROLL_MILLISECONDS = \"fileRollMilliseconds\";\n  public static final String FILE_ROLL_MAX_ROLLS = \"fileRollMaxRolls\";\n  public static final String TRUSTED = \"trusted\";\n  public static final String STATSD = \"statsd\";\n  public static final String PROBE_DESC_PATH = \"probeDescPath\";\n  public static final String DEBUG = \"debug\";\n  public static final String PORT = \"port\";\n  public static final String STDOUT = \"stdout\";\n  public static final String NO_SERVER = \"noServer\";\n  public static final String HELP = \"help\";\n  public static final String LIBS = \"libs\";\n  public static final String GRANT = \"grant\";\n  public static final String DENY = \"deny\";\n  public static final String GRANT_ALL = \"grantAll\";\n  public static final String ALLOW_EXTENSIONS = \"allowExtensions\";\n  public static final String DENY_EXTENSIONS = \"denyExtensions\";\n  public static final String ALLOW_PRIVILEGED = \"allowPrivileged\";\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/ArgsMap.java",
    "content": "/*\n * Copyright (c) 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\npackage org.openjdk.btrace.core;\n\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/** A simple argument map wrapper allowing indexed access */\npublic final class ArgsMap implements Iterable<Map.Entry<String, String>> {\n  private final LinkedHashMap<String, String> map;\n\n  public ArgsMap(Map<String, String> args) {\n    map = args != null ? new LinkedHashMap<>(args) : new LinkedHashMap<>();\n  }\n\n  public ArgsMap(String[] argLine) {\n    map = new LinkedHashMap<>();\n    if (argLine != null) {\n      for (String arg : argLine) {\n        String[] kv = arg.split(\"=\");\n        if (kv.length != 2) {\n          map.put(arg, \"\");\n        } else {\n          map.put(kv[0], kv[1]);\n        }\n      }\n    }\n  }\n\n  public ArgsMap() {\n    this((Map<String, String>) null);\n  }\n\n  public ArgsMap(int initialCapacity) {\n    map = new LinkedHashMap<>(initialCapacity);\n  }\n\n  public static ArgsMap merge(ArgsMap... maps) {\n    Map<String, String> propMap = new LinkedHashMap<>();\n    for (ArgsMap map : maps) {\n      propMap.putAll(map.map);\n    }\n    return new ArgsMap(propMap);\n  }\n\n  public String get(String key) {\n    return map.get(key);\n  }\n\n  public String get(int idx) {\n    if (idx >= 0 && idx < map.size()) {\n      Iterator<Map.Entry<String, String>> argsIterator = map.entrySet().iterator();\n      for (int i = 0; i < idx; i++) {\n        argsIterator.next();\n      }\n      Map.Entry<String, String> e = argsIterator.next();\n      return e.getValue() != null ? e.getKey() + \"=\" + e.getValue() : e.getKey();\n    } else {\n      return null;\n    }\n  }\n\n  public void clear() {\n    map.clear();\n  }\n\n  public int size() {\n    return map.size();\n  }\n\n  public boolean isEmpty() {\n    return map.isEmpty();\n  }\n\n  public String put(String key, String value) {\n    return map.put(key, value);\n  }\n\n  @Override\n  public Iterator<Map.Entry<String, String>> iterator() {\n    return map.entrySet().iterator();\n  }\n\n  public boolean containsKey(String key) {\n    return map.containsKey(key);\n  }\n\n  @Override\n  public boolean equals(Object o) {\n    return map.equals(o);\n  }\n\n  @Override\n  public int hashCode() {\n    return map.hashCode();\n  }\n\n  @Override\n  public String toString() {\n    return \"ArgsMap{\" + \"map=\" + map + '}';\n  }\n\n  public String template(String value) {\n    if (value == null) {\n      return null;\n    }\n    if (value.isEmpty()) {\n      return value;\n    }\n\n    Matcher matcher = PatternSingleton.INSTANCE.matcher(value);\n    StringBuffer buffer = new StringBuffer(value.length());\n\n    while (matcher.find()) {\n      String val = get(matcher.group(1));\n      matcher.appendReplacement(buffer, val != null ? val : \"$0\");\n    }\n    matcher.appendTail(buffer);\n\n    return buffer.toString();\n  }\n\n  private static final class PatternSingleton {\n    // lazy initialization trick\n    // do not compile the pattern until it is actually requested\n    private static final Pattern INSTANCE = Pattern.compile(\"\\\\$\\\\{(.*?)}\");\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/BTraceRuntime.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core;\n\nimport com.sun.management.HotSpotDiagnosticMXBean;\nimport java.io.BufferedOutputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectOutputStream;\nimport java.lang.instrument.Instrumentation;\nimport java.lang.management.GarbageCollectorMXBean;\nimport java.lang.management.LockInfo;\nimport java.lang.management.MemoryMXBean;\nimport java.lang.management.MemoryPoolMXBean;\nimport java.lang.management.MemoryUsage;\nimport java.lang.management.MonitorInfo;\nimport java.lang.management.OperatingSystemMXBean;\nimport java.lang.management.RuntimeMXBean;\nimport java.lang.management.ThreadInfo;\nimport java.lang.management.ThreadMXBean;\nimport java.security.AccessController;\nimport java.security.PrivilegedAction;\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.WeakHashMap;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicLong;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\nimport org.openjdk.btrace.core.types.AnyType;\nimport org.openjdk.btrace.core.types.BTraceCollection;\nimport org.openjdk.btrace.core.types.BTraceDeque;\nimport org.openjdk.btrace.core.types.BTraceMap;\nimport sun.misc.Unsafe;\n\n@SuppressWarnings(\"deprecation\")\npublic final class BTraceRuntime {\n\n  public static final String CMD_QUEUE_LIMIT_KEY = \"org.openjdk.btrace.core.cmdQueueLimit\";\n  private static final boolean messageTimestamp = false;\n  private static final String LINE_SEPARATOR;\n  // perf counter variability - we always variable variability\n  private static final int V_Variable = 3;\n  // perf counter units\n  private static final int V_None = 1;\n  private static final int V_String = 5;\n  private static final int PERF_STRING_LIMIT = 256;\n  // the number of stack frames taking a thread dump adds\n  private static final int THRD_DUMP_FRAMES = 1;\n\n  // we need Unsafe to load BTrace class bytes as\n  // bootstrap class\n  private static volatile Unsafe unsafe = null;\n  private static Properties dotWriterProps;\n  // this field is 'back-set' by the agent at startup thus needs to remain non-final\n  private static volatile BTraceRuntimeAccessor rtAccessor = () -> null;\n  private static final String INDENT = \"    \";\n\n  public static volatile Instrumentation instrumentation = null;\n\n  static {\n    LINE_SEPARATOR = System.getProperty(\"line.separator\");\n  }\n\n  private BTraceRuntime() {}\n\n  private static Impl getRt() {\n    Impl rt = rtAccessor.getRt();\n    return rt;\n  }\n\n  public static long parseLong(String value, long deflt) {\n    if (value == null) {\n      return deflt;\n    }\n    try {\n      return Long.parseLong(value);\n    } catch (NumberFormatException e) {\n      return deflt;\n    }\n  }\n\n  public static int parseInt(String value, int deflt) {\n    if (value == null) {\n      return deflt;\n    }\n    try {\n      return Integer.parseInt(value);\n    } catch (NumberFormatException e) {\n      return deflt;\n    }\n  }\n\n  // The following constants are copied from VM code\n  // for jvmstat.\n\n  public static Unsafe initUnsafe() {\n    try {\n      if (unsafe == null) {\n        unsafe = Unsafe.getUnsafe();\n      }\n    } catch (SecurityException e) {\n      System.err.println(\"BTrace warning: unable to initialize Unsafe. BTrace will not function properly\");\n    }\n    return unsafe;\n  }\n\n  static int getInstrumentationLevel() {\n    return getRt().getInstrumentationLevel();\n  }\n\n  static void setInstrumentationLevel(int level) {\n    getRt().setInstrumentationLevel(level);\n  }\n\n  public static boolean enter() {\n    BTraceRuntime.Impl rt = getRt();\n    return rt == null || rt.enter();\n  }\n\n  /**\n   * Leave method is called by every probed method just before the probe actions end (and actual\n   * probed method continues).\n   */\n  public static void leave() {\n    BTraceRuntime.Impl rt = getRt();\n    if (rt != null) {\n      rt.leave();\n    }\n  }\n\n  /** Handles exception from BTrace probe actions. */\n  public static void handleException(Throwable th) {\n    getRt().handleException(th);\n  }\n\n  // package-private interface to BTraceUtils class.\n\n  private static String identityStr(Object obj) {\n    int hashCode = java.lang.System.identityHashCode(obj);\n    return obj.getClass().getName() + \"@\" + Integer.toHexString(hashCode);\n  }\n\n  static int speculation() {\n    return getRt().speculation();\n  }\n\n  static void speculate(int id) {\n    getRt().speculate(id);\n  }\n\n  static void discard(int id) {\n    getRt().discard(id);\n  }\n\n  static void commit(int id) {\n    getRt().commit(id);\n  }\n\n  /**\n   * Indicates whether two given objects are \"equal to\" one another. For bootstrap classes, returns\n   * the result of calling Object.equals() override. For non-bootstrap classes, the reference\n   * identity comparison is done.\n   *\n   * @param obj1 first object to compare equality\n   * @param obj2 second object to compare equality\n   * @return <code>true</code> if the given objects are equal; <code>false</code> otherwise.\n   */\n  static boolean compare(Object obj1, Object obj2) {\n    if (obj1 instanceof String) {\n      return obj1.equals(obj2);\n    } else if (obj1.getClass().getClassLoader() == null) {\n      if (obj2 == null || obj2.getClass().getClassLoader() == null) {\n        return obj1.equals(obj2);\n      } // else fall through..\n    }\n    return obj1 == obj2;\n  }\n\n  // BTrace map functions\n  static <K, V> Map<K, V> newHashMap() {\n    return new BTraceMap<>(new HashMap<>());\n  }\n\n  static <K, V> Map<K, V> newWeakMap() {\n    return new BTraceMap<>(new WeakHashMap<>());\n  }\n\n  static <V> Deque<V> newDeque() {\n    return new BTraceDeque<>(new ArrayDeque<>());\n  }\n\n  static Appendable newStringBuilder(boolean threadSafe) {\n    return threadSafe ? new StringBuffer() : new StringBuilder();\n  }\n\n  static Appendable newStringBuilder() {\n    return newStringBuilder(false);\n  }\n\n  static <E> int size(Collection<E> coll) {\n    if (coll instanceof BTraceCollection || coll.getClass().getClassLoader() == null) {\n      return coll.size();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  public static <E> boolean isEmpty(Collection<E> coll) {\n    if (coll instanceof BTraceCollection || coll.getClass().getClassLoader() == null) {\n      return coll.isEmpty();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static <E> boolean contains(Collection<E> coll, Object obj) {\n    if (coll instanceof BTraceCollection || coll.getClass().getClassLoader() == null) {\n      for (E e : coll) {\n        if (compare(e, obj)) {\n          return true;\n        }\n      }\n      return false;\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static <E> Object[] toArray(Collection<E> collection) {\n    if (collection == null) {\n      return new Object[0];\n    } else {\n      return collection.toArray();\n    }\n  }\n\n  static <K, V> V get(Map<K, V> map, K key) {\n    if (map instanceof BTraceMap || map.getClass().getClassLoader() == null) {\n      return map.get(key);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static <K, V> boolean containsKey(Map<K, V> map, K key) {\n    if (map instanceof BTraceMap || map.getClass().getClassLoader() == null) {\n      return map.containsKey(key);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static <K, V> boolean containsValue(Map<K, V> map, V value) {\n    if (map instanceof BTraceMap || map.getClass().getClassLoader() == null) {\n      return map.containsValue(value);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static <K, V> V put(Map<K, V> map, K key, V value) {\n    if (map instanceof BTraceMap) {\n      return map.put(key, value);\n    } else {\n      throw new IllegalArgumentException(\"not a btrace map\");\n    }\n  }\n\n  static <K, V> V remove(Map<K, V> map, K key) {\n    if (map instanceof BTraceMap) {\n      return map.remove(key);\n    } else {\n      throw new IllegalArgumentException(\"not a btrace map\");\n    }\n  }\n\n  static <K, V> void clear(Map<K, V> map) {\n    if (map instanceof BTraceMap) {\n      map.clear();\n    } else {\n      throw new IllegalArgumentException(\"not a btrace map\");\n    }\n  }\n\n  static <K, V> int size(Map<K, V> map) {\n    if (map instanceof BTraceMap || map.getClass().getClassLoader() == null) {\n      return map.size();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static <K, V> boolean isEmpty(Map<K, V> map) {\n    if (map instanceof BTraceMap || map.getClass().getClassLoader() == null) {\n      return map.isEmpty();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static <K, V> void putAll(Map<K, V> src, Map<K, V> dst) {\n    dst.putAll(src);\n  }\n\n  static <K, V> void copy(Map<K, V> src, Map<K, V> dst) {\n    dst.clear();\n    dst.putAll(src);\n  }\n\n  @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n  static void printMap(Map map) {\n    if (map instanceof BTraceMap || map.getClass().getClassLoader() == null) {\n      synchronized (map) {\n        Map<String, String> m = new HashMap<>();\n        @SuppressWarnings(\"unchecked\")\n        Set<Map.Entry<Object, Object>> entries = map.entrySet();\n        for (Map.Entry<Object, Object> e : entries) {\n          m.put(BTraceUtils.Strings.str(e.getKey()), BTraceUtils.Strings.str(e.getValue()));\n        }\n        printStringMap(null, m);\n      }\n    } else {\n      print(BTraceUtils.Strings.str(map));\n    }\n  }\n\n  public static <V> void push(Deque<V> queue, V value) {\n    if (queue instanceof BTraceDeque || queue.getClass().getClassLoader() == null) {\n      queue.push(value);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  public static <V> void addLast(Deque<V> queue, V value) {\n    if (queue instanceof BTraceDeque || queue.getClass().getClassLoader() == null) {\n      queue.addLast(value);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  public static <V> V peekFirst(Deque<V> queue) {\n    if (queue instanceof BTraceDeque || queue.getClass().getClassLoader() == null) {\n      return queue.peekFirst();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  public static <V> V peekLast(Deque<V> queue) {\n    if (queue instanceof BTraceDeque || queue.getClass().getClassLoader() == null) {\n      return queue.peekLast();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  public static <V> V removeLast(Deque<V> queue) {\n    if (queue instanceof BTraceDeque || queue.getClass().getClassLoader() == null) {\n      return queue.removeLast();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  public static <V> V removeFirst(Deque<V> queue) {\n    if (queue instanceof BTraceDeque || queue.getClass().getClassLoader() == null) {\n      return queue.removeFirst();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  public static <V> V poll(Deque<V> queue) {\n    if (queue instanceof BTraceDeque || queue.getClass().getClassLoader() == null) {\n      return queue.poll();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  public static <V> V peek(Deque<V> queue) {\n    if (queue instanceof BTraceDeque || queue.getClass().getClassLoader() == null) {\n      return queue.peek();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  public static <V> void clear(Deque<V> queue) {\n    if (queue instanceof BTraceDeque || queue.getClass().getClassLoader() == null) {\n      queue.clear();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  public static Appendable append(Appendable buffer, String strToAppend) {\n    try {\n      if (buffer != null && strToAppend != null) {\n        return buffer.append(strToAppend);\n      } else {\n        throw new IllegalArgumentException();\n      }\n    } catch (IOException e) {\n      throw new IllegalArgumentException(e);\n    }\n  }\n\n  public static int length(Appendable buffer) {\n    if (buffer instanceof CharSequence) {\n      return ((CharSequence) buffer).length();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static void printNumber(String name, Number value) {\n    getRt().sendNumberData(name, value);\n  }\n\n  static void printNumberMap(String name, Map<String, ? extends Number> data) {\n    getRt().sendNumberMapData(name, data);\n  }\n\n  static void printStringMap(String name, Map<String, String> data) {\n    getRt().sendStringMapData(name, data);\n  }\n\n  // BTrace exit built-in function\n  static void exit(int exitCode) {\n    getRt().exit(exitCode);\n  }\n\n  static long sizeof(Object obj) {\n    return getRt().sizeof(obj);\n  }\n\n  // BTrace command line argument functions\n  static int $length() {\n    return getRt().$length();\n  }\n\n  static String $(int n) {\n    return getRt().$(n);\n  }\n\n  static String $(String key) {\n    return getRt().$(key);\n  }\n\n  /**\n   * @see BTraceUtils#instanceOf(java.lang.Object, java.lang.String)\n   */\n  static boolean instanceOf(Object obj, String className) {\n    if (obj instanceof AnyType) {\n      // the only time we can have AnyType on stack\n      // is if it was passed in as a placeholder\n      // for void @Return parameter value\n      if (className.equalsIgnoreCase(\"void\")) {\n        return obj.equals(AnyType.VOID);\n      }\n      return false;\n    }\n    Class<?> objClass = obj.getClass();\n    ClassLoader cl = objClass.getClassLoader();\n    cl = cl != null ? cl : ClassLoader.getSystemClassLoader();\n    try {\n      Class<?> target = cl.loadClass(className);\n      return target.isAssignableFrom(objClass);\n    } catch (ClassNotFoundException e) {\n      // non-existing class\n      return false;\n    }\n  }\n\n  static AtomicInteger newAtomicInteger(int initVal) {\n    return new BTraceAtomicInteger(initVal);\n  }\n\n  static int get(AtomicInteger ai) {\n    if (ai instanceof BTraceAtomicInteger || ai.getClass().getClassLoader() == null) {\n      return ai.get();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static void set(AtomicInteger ai, int i) {\n    if (ai instanceof BTraceAtomicInteger) {\n      ai.set(i);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static void lazySet(AtomicInteger ai, int i) {\n    if (ai instanceof BTraceAtomicInteger) {\n      ai.lazySet(i);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static boolean compareAndSet(AtomicInteger ai, int i, int j) {\n    if (ai instanceof BTraceAtomicInteger) {\n      return ai.compareAndSet(i, j);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static boolean weakCompareAndSet(AtomicInteger ai, int i, int j) {\n    if (ai instanceof BTraceAtomicInteger) {\n      return ai.weakCompareAndSet(i, j);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static int getAndIncrement(AtomicInteger ai) {\n    if (ai instanceof BTraceAtomicInteger) {\n      return ai.getAndIncrement();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static int getAndDecrement(AtomicInteger ai) {\n    if (ai instanceof BTraceAtomicInteger) {\n      return ai.getAndDecrement();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static int incrementAndGet(AtomicInteger ai) {\n    if (ai instanceof BTraceAtomicInteger) {\n      return ai.incrementAndGet();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static int decrementAndGet(AtomicInteger ai) {\n    if (ai instanceof BTraceAtomicInteger) {\n      return ai.decrementAndGet();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static int getAndAdd(AtomicInteger ai, int i) {\n    if (ai instanceof BTraceAtomicInteger) {\n      return ai.getAndAdd(i);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static int addAndGet(AtomicInteger ai, int i) {\n    if (ai instanceof BTraceAtomicInteger) {\n      return ai.addAndGet(i);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static int getAndSet(AtomicInteger ai, int i) {\n    if (ai instanceof BTraceAtomicInteger) {\n      return ai.getAndSet(i);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static AtomicLong newAtomicLong(long initVal) {\n    return new BTraceAtomicLong(initVal);\n  }\n\n  static long get(AtomicLong al) {\n    if (al instanceof BTraceAtomicLong || al.getClass().getClassLoader() == null) {\n      return al.get();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static void set(AtomicLong al, long i) {\n    if (al instanceof BTraceAtomicLong) {\n      al.set(i);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static void lazySet(AtomicLong al, long i) {\n    if (al instanceof BTraceAtomicLong) {\n      al.lazySet(i);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static boolean compareAndSet(AtomicLong al, long i, long j) {\n    if (al instanceof BTraceAtomicLong) {\n      return al.compareAndSet(i, j);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static boolean weakCompareAndSet(AtomicLong al, long i, long j) {\n    if (al instanceof BTraceAtomicLong) {\n      return al.weakCompareAndSet(i, j);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static long getAndIncrement(AtomicLong al) {\n    if (al instanceof BTraceAtomicLong) {\n      return al.getAndIncrement();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static long getAndDecrement(AtomicLong al) {\n    if (al instanceof BTraceAtomicLong) {\n      return al.getAndDecrement();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static long incrementAndGet(AtomicLong al) {\n    if (al instanceof BTraceAtomicLong) {\n      return al.incrementAndGet();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static long decrementAndGet(AtomicLong al) {\n    if (al instanceof BTraceAtomicLong) {\n      return al.decrementAndGet();\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static long getAndAdd(AtomicLong al, long i) {\n    if (al instanceof BTraceAtomicLong) {\n      return al.getAndAdd(i);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static long addAndGet(AtomicLong al, long i) {\n    if (al instanceof BTraceAtomicLong) {\n      return al.addAndGet(i);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  static long getAndSet(AtomicLong al, long i) {\n    if (al instanceof BTraceAtomicLong) {\n      return al.getAndSet(i);\n    } else {\n      throw new IllegalArgumentException();\n    }\n  }\n\n  // BTrace perf counter reading functions\n  static int perfInt(String name) {\n    return getRt().perfInt(name);\n  }\n\n  static long perfLong(String name) {\n    return getRt().perfLong(name);\n  }\n\n  static String perfString(String name) {\n    return getRt().perfString(name);\n  }\n\n  // stack trace functions\n  private static String stackTraceAllStr(int numFrames, boolean printWarning) {\n    Set<Map.Entry<Thread, StackTraceElement[]>> traces = Thread.getAllStackTraces().entrySet();\n    StringBuilder buf = new StringBuilder();\n    for (Map.Entry<Thread, StackTraceElement[]> t : traces) {\n      buf.append(t.getKey());\n      buf.append(LINE_SEPARATOR);\n      buf.append(LINE_SEPARATOR);\n      StackTraceElement[] st = t.getValue();\n      buf.append(stackTraceStr(\"\\t\", st, 0, numFrames, printWarning));\n      buf.append(LINE_SEPARATOR);\n    }\n    return buf.toString();\n  }\n\n  static String stackTraceAllStr(int numFrames) {\n    return stackTraceAllStr(numFrames, false);\n  }\n\n  static void stackTraceAll(int numFrames) {\n    getRt().send(stackTraceAllStr(numFrames, true));\n  }\n\n  static String stackTraceStr(StackTraceElement[] st, int strip, int numFrames) {\n    return stackTraceStr(null, st, strip, numFrames, false);\n  }\n\n  static String stackTraceStr(String prefix, StackTraceElement[] st, int strip, int numFrames) {\n    return stackTraceStr(prefix, st, strip, numFrames, false);\n  }\n\n  private static String stackTraceStr(\n      String prefix, StackTraceElement[] st, int strip, int numFrames, boolean printWarning) {\n    strip = strip > 0 ? strip + THRD_DUMP_FRAMES : 0;\n    numFrames = numFrames > 0 ? numFrames : st.length - strip;\n\n    int limit = strip + numFrames;\n    limit = Math.min(limit, st.length);\n\n    if (prefix == null) {\n      prefix = \"\";\n    }\n\n    StringBuilder buf = new StringBuilder();\n    for (int i = strip; i < limit; i++) {\n      buf.append(prefix);\n      buf.append(st[i]);\n      buf.append(LINE_SEPARATOR);\n    }\n    if (printWarning && limit < st.length) {\n      buf.append(prefix);\n      buf.append(st.length - limit);\n      buf.append(\" more frame(s) ...\");\n      buf.append(LINE_SEPARATOR);\n    }\n    return buf.toString();\n  }\n\n  static void stackTrace(StackTraceElement[] st, int strip, int numFrames) {\n    stackTrace(null, st, strip, numFrames);\n  }\n\n  static void stackTrace(String prefix, StackTraceElement[] st, int strip, int numFrames) {\n    getRt().send(stackTraceStr(prefix, st, strip, numFrames, true));\n  }\n\n  // print/println functions\n  static void print(String str) {\n    getRt().send(str);\n  }\n\n  static void println(String str) {\n    getRt().send(str + LINE_SEPARATOR);\n  }\n\n  static void println() {\n    getRt().send(LINE_SEPARATOR);\n  }\n\n  static String property(String name) {\n    return AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty(name));\n  }\n\n  static Properties properties() {\n    return AccessController.doPrivileged(\n        (PrivilegedAction<Properties>) () -> System.getProperties());\n  }\n\n  static String getenv(String name) {\n    return AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getenv(name));\n  }\n\n  static Map<String, String> getenv() {\n    return AccessController.doPrivileged(\n        (PrivilegedAction<Map<String, String>>) () -> System.getenv());\n  }\n\n  static MemoryUsage heapUsage() {\n    return getRt().getMemoryMXBean().getHeapMemoryUsage();\n  }\n\n  static MemoryUsage nonHeapUsage() {\n    return getRt().getMemoryMXBean().getNonHeapMemoryUsage();\n  }\n\n  static long finalizationCount() {\n    return getRt().getMemoryMXBean().getObjectPendingFinalizationCount();\n  }\n\n  static long vmStartTime() {\n    return getRt().getRuntimeMXBean().getStartTime();\n  }\n\n  static long vmUptime() {\n    return getRt().getRuntimeMXBean().getUptime();\n  }\n\n  static List<String> getInputArguments() {\n    return getRt().getRuntimeMXBean().getInputArguments();\n  }\n\n  static String getVmVersion() {\n    return getRt().getRuntimeMXBean().getVmVersion();\n  }\n\n  static boolean isBootClassPathSupported() {\n    return getRt().getRuntimeMXBean().isBootClassPathSupported();\n  }\n\n  static String getBootClassPath() {\n    return getRt().getRuntimeMXBean().getBootClassPath();\n  }\n\n  static long getThreadCount() {\n    return getRt().getThreadMXBean().getThreadCount();\n  }\n\n  static long getPeakThreadCount() {\n    return getRt().getThreadMXBean().getPeakThreadCount();\n  }\n\n  static long getTotalStartedThreadCount() {\n    return getRt().getThreadMXBean().getTotalStartedThreadCount();\n  }\n\n  static long getDaemonThreadCount() {\n    return getRt().getThreadMXBean().getDaemonThreadCount();\n  }\n\n  static long getCurrentThreadCpuTime() {\n    ThreadMXBean threadMXBean = getRt().getThreadMXBean();\n    threadMXBean.setThreadCpuTimeEnabled(true);\n    return threadMXBean.getCurrentThreadCpuTime();\n  }\n\n  static long getCurrentThreadUserTime() {\n    ThreadMXBean threadMXBean = getRt().getThreadMXBean();\n    threadMXBean.setThreadCpuTimeEnabled(true);\n    return threadMXBean.getCurrentThreadUserTime();\n  }\n\n  static void dumpHeap(String fileName, boolean live) {\n    try {\n      String name = getRt().resolveFileName(fileName);\n      getRt().getHotspotMBean().dumpHeap(name, live);\n    } catch (RuntimeException re) {\n      throw re;\n    } catch (Exception exp) {\n      throw new RuntimeException(exp);\n    }\n  }\n\n  static long getTotalGcTime() {\n    long totalGcTime = 0;\n    for (GarbageCollectorMXBean gcBean : getRt().getGCMBeans()) {\n      totalGcTime += gcBean.getCollectionTime();\n    }\n    return totalGcTime;\n  }\n\n  static String getMemoryPoolUsage(String poolFormat) {\n    if (poolFormat == null) {\n      poolFormat = \"%1$s;%2$d;%3$d;%4$d;%5$d\";\n    }\n    List<MemoryPoolMXBean> memPoolList = getRt().getMemoryPoolMXBeans();\n    Object[][] poolOutput = new Object[memPoolList.size()][5];\n\n    StringBuilder membuffer = new StringBuilder();\n\n    for (int i = 0; i < memPoolList.size(); i++) {\n      MemoryPoolMXBean memPool = memPoolList.get(i);\n      poolOutput[i][0] = memPool.getName();\n      poolOutput[i][1] = memPool.getUsage().getMax();\n      poolOutput[i][2] = memPool.getUsage().getUsed();\n      poolOutput[i][3] = memPool.getUsage().getCommitted();\n      poolOutput[i][4] = memPool.getUsage().getInit();\n    }\n    for (Object[] memPoolOutput : poolOutput) {\n      membuffer.append(String.format(poolFormat, memPoolOutput)).append(\"\\n\");\n    }\n\n    return membuffer.toString();\n  }\n\n  static double getSystemLoadAverage() {\n    return getRt().getOperatingSystemMXBean().getSystemLoadAverage();\n  }\n\n  static long getProcessCPUTime() {\n    OperatingSystemMXBean mbean = getRt().getOperatingSystemMXBean();\n\n    if (mbean instanceof com.sun.management.OperatingSystemMXBean) {\n      return ((com.sun.management.OperatingSystemMXBean) mbean).getProcessCpuTime();\n    }\n\n    return -1;\n  }\n\n  static void serialize(Object obj, String fileName) {\n    try {\n      BufferedOutputStream bos =\n          new BufferedOutputStream(new FileOutputStream(getRt().resolveFileName(fileName)));\n      try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {\n        oos.writeObject(obj);\n      }\n    } catch (RuntimeException re) {\n      throw re;\n    } catch (Exception exp) {\n      throw new RuntimeException(exp);\n    }\n  }\n\n  static String toXML(Object obj) {\n    return getRt().toXML(obj);\n  }\n\n  static void writeXML(Object obj, String fileName) {\n    getRt().writeXML(obj, fileName);\n  }\n\n  static void writeDOT(Object obj, String fileName) {\n    getRt().writeDOT(obj, fileName);\n  }\n\n  static void deadlocks(boolean stackTrace) {\n    ThreadMXBean mbean = getRt().getThreadMXBean();\n    if (mbean.isSynchronizerUsageSupported()) {\n      long[] tids = mbean.findDeadlockedThreads();\n      if (tids != null && tids.length > 0) {\n        ThreadInfo[] infos = mbean.getThreadInfo(tids, true, true);\n        StringBuilder sb = new StringBuilder();\n        for (ThreadInfo ti : infos) {\n          sb.append(\"\\\"\")\n              .append(ti.getThreadName())\n              .append(\"\\\"\" + \" Id=\")\n              .append(ti.getThreadId())\n              .append(\" in \")\n              .append(ti.getThreadState());\n          if (ti.getLockName() != null) {\n            sb.append(\" on lock=\").append(ti.getLockName());\n          }\n          if (ti.isSuspended()) {\n            sb.append(\" (suspended)\");\n          }\n          if (ti.isInNative()) {\n            sb.append(\" (running in native)\");\n          }\n          if (ti.getLockOwnerName() != null) {\n            sb.append(INDENT)\n                .append(\" owned by \")\n                .append(ti.getLockOwnerName())\n                .append(\" Id=\")\n                .append(ti.getLockOwnerId());\n            sb.append(LINE_SEPARATOR);\n          }\n\n          if (stackTrace) {\n            // print stack trace with locks\n            StackTraceElement[] stacktrace = ti.getStackTrace();\n            MonitorInfo[] monitors = ti.getLockedMonitors();\n            for (int i = 0; i < stacktrace.length; i++) {\n              StackTraceElement ste = stacktrace[i];\n              sb.append(INDENT).append(\"at \").append(ste);\n              sb.append(LINE_SEPARATOR);\n              for (MonitorInfo mi : monitors) {\n                if (mi.getLockedStackDepth() == i) {\n                  sb.append(INDENT).append(\"  - locked \").append(mi);\n                  sb.append(LINE_SEPARATOR);\n                }\n              }\n            }\n            sb.append(LINE_SEPARATOR);\n          }\n\n          LockInfo[] locks = ti.getLockedSynchronizers();\n          sb.append(INDENT).append(\"Locked synchronizers: count = \").append(locks.length);\n          sb.append(LINE_SEPARATOR);\n          for (LockInfo li : locks) {\n            sb.append(INDENT).append(\"  - \").append(li);\n            sb.append(LINE_SEPARATOR);\n          }\n          sb.append(LINE_SEPARATOR);\n        }\n        getRt().send(sb.toString());\n      }\n    }\n  }\n\n  static int dtraceProbe(String s1, String s2, int i1, int i2) {\n    if (getRt().isDTraceEnabled()) {\n      return dtraceProbe0(s1, s2, i1, i2);\n    } else {\n      return 0;\n    }\n  }\n\n  //  called from instrumentation initialization code\n  public static JfrEvent.Factory createEventFactory(JfrEvent.Template template) {\n    return getRt().createEventFactory(template);\n  }\n\n  public static boolean isBootstrapClass(String className) {\n    return getRt().isBootstrapClass(className);\n  }\n\n  static void printSnapshot(String name, Profiler.Snapshot snapshot) {\n    getRt().sendGridData(name, snapshot.getGridData());\n  }\n\n  /**\n   * Prints profiling snapshot using the provided format\n   *\n   * @param name The name of the aggregation to be used in the textual output\n   * @param snapshot The snapshot to print\n   * @param format The format to use. It mimics {@linkplain String#format(java.lang.String,\n   *     java.lang.Object[]) } behaviour with the addition of the ability to address the key title\n   *     as a 0-indexed item\n   * @see String#format(java.lang.String, java.lang.Object[])\n   */\n  static void printSnapshot(String name, Profiler.Snapshot snapshot, String format) {\n    getRt().sendGridData(name, snapshot.getGridData(), format);\n  }\n\n  /**\n   * @see BTraceUtils.Profiling#newProfiler()\n   */\n  static Profiler newProfiler() {\n    return getRt().newProfiler();\n  }\n\n  /**\n   * @see BTraceUtils.Profiling#newProfiler(int)\n   */\n  static Profiler newProfiler(int expectedMethodCnt) {\n    return getRt().newProfiler(expectedMethodCnt);\n  }\n\n  /**\n   * @see BTraceUtils.Profiling#recordEntry(Profiler, java.lang.String)\n   */\n  static void recordEntry(Profiler profiler, String methodName) {\n    profiler.recordEntry(methodName);\n  }\n\n  // profiling related methods\n\n  /**\n   * @see BTraceUtils.Profiling#recordExit(Profiler, java.lang.String, long)\n   */\n  static void recordExit(Profiler profiler, String methodName, long duration) {\n    profiler.recordExit(methodName, duration);\n  }\n\n  /**\n   * @see BTraceUtils.Profiling#snapshot(Profiler)\n   */\n  static Profiler.Snapshot snapshot(Profiler profiler) {\n    return profiler.snapshot();\n  }\n\n  /**\n   * @see BTraceUtils.Profiling#snapshotAndReset(Profiler)\n   */\n  static Profiler.Snapshot snapshotAndReset(Profiler profiler) {\n    return profiler.snapshot(true);\n  }\n\n  static void resetProfiler(Profiler profiler) {\n    profiler.reset();\n  }\n\n  static ClassLoader getCallerClassloader(int stackDec) {\n    return getRt().getCallerClassLoader(stackDec + 1);\n  }\n\n  public static Class<?> getCallerClass(int stackDec) {\n    return getRt().getCallerClass(stackDec + 1);\n  }\n\n  // private methods below this point\n  // raise DTrace USDT probe\n  private static native int dtraceProbe0(String s1, String s2, int i1, int i2);\n\n  /**\n   * Common BTrace runtime interface allowing access from various subsystems (core, runtime,\n   * instrumentation, clients)\n   */\n  public interface Impl {\n    void send(String msg);\n\n    void sendCommand(Object cmd);\n\n    void sendNumberData(String name, Number value);\n\n    void sendNumberMapData(String name, Map<String, ? extends Number> data);\n\n    void sendStringMapData(String name, Map<String, String> data);\n\n    void sendGridData(String name, List<Object[]> data);\n\n    void sendGridData(String name, List<Object[]> data, String format);\n\n    boolean enter();\n\n    void leave();\n\n    int getInstrumentationLevel();\n\n    void setInstrumentationLevel(int level);\n\n    void handleException(Throwable th);\n\n    int speculation();\n\n    void speculate(int id);\n\n    void commit(int id);\n\n    void discard(int id);\n\n    void exit(int exitCode);\n\n    long sizeof(Object obj);\n\n    int $length();\n\n    String $(int n);\n\n    String $(String key);\n\n    String toXML(Object obj);\n\n    void writeXML(Object obj, String fileName);\n\n    void writeDOT(Object obj, String fileName);\n\n    Profiler newProfiler();\n\n    Profiler newProfiler(int expectedMethodCnt);\n\n    int perfInt(String name);\n\n    long perfLong(String name);\n\n    String perfString(String name);\n\n    String resolveFileName(String name);\n\n    boolean isDTraceEnabled();\n\n    void handleEvent(Object cmd);\n\n    void handleExit(int i);\n\n    void shutdownCmdLine();\n\n    List<MemoryPoolMXBean> getMemoryPoolMXBeans();\n\n    HotSpotDiagnosticMXBean getHotspotMBean();\n\n    MemoryMXBean getMemoryMXBean();\n\n    RuntimeMXBean getRuntimeMXBean();\n\n    ThreadMXBean getThreadMXBean();\n\n    OperatingSystemMXBean getOperatingSystemMXBean();\n\n    List<GarbageCollectorMXBean> getGCMBeans();\n\n    Class<?> defineClass(byte[] code);\n\n    ClassLoader getCallerClassLoader(int stackDec);\n\n    Class<?> getCallerClass(int stackDec);\n\n    JfrEvent.Factory createEventFactory(JfrEvent.Template template);\n\n    int version();\n\n    boolean isBootstrapClass(String className);\n\n    String getClassName();\n  }\n\n  public interface BTraceRuntimeAccessor {\n    Impl getRt();\n  }\n\n  private static final class BTraceAtomicInteger extends AtomicInteger {\n    BTraceAtomicInteger(int initVal) {\n      super(initVal);\n    }\n  }\n\n  private static final class BTraceAtomicLong extends AtomicLong {\n    BTraceAtomicLong(long initVal) {\n      super(initVal);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/BTraceRuntimeBridge.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage org.openjdk.btrace.core;\n\n/**\n * Minimal bootstrap-visible bridge used by injected code to reach the runtime implementation.\n */\npublic interface BTraceRuntimeBridge {\n  void start();\n\n  void leave();\n\n  void handleException(Throwable th);\n\n  boolean isDisabled();\n\n  void newPerfCounter(Object value, String name, String desc);\n\n  int getPerfInt(String name);\n\n  void putPerfInt(int value, String name);\n\n  float getPerfFloat(String name);\n\n  void putPerfFloat(float value, String name);\n\n  long getPerfLong(String name);\n\n  void putPerfLong(long value, String name);\n\n  String getPerfString(String name);\n\n  void putPerfString(String value, String name);\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/BTraceUtils.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core;\n\nimport java.io.Serializable;\nimport java.lang.management.MemoryUsage;\nimport java.lang.ref.Reference;\nimport java.lang.ref.SoftReference;\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.security.AccessController;\nimport java.security.PrivilegedAction;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Properties;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.regex.Pattern;\nimport java.util.regex.PatternSyntaxException;\nimport jdk.jfr.Event;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/**\n * This class is an all-in-one wrapper for BTrace DSL methods\n *\n * @author A. Sundararajan\n * @author Jaroslav Bachorik\n */\npublic class BTraceUtils {\n  // standard stack depth decrement for figuring out the caller class calls\n  private static final int STACK_DEC = 2;\n\n  static {\n    BTraceRuntime.initUnsafe();\n  }\n\n  // do not allow object creation!\n  private BTraceUtils() {}\n\n  // Thread and stack access\n\n  /**\n   * Tests whether this thread has been interrupted. The <i>interrupted status</i> of the thread is\n   * unaffected by this method.\n   *\n   * <p>A thread interruption ignored because a thread was not alive at the time of the interrupt\n   * will be reflected by this method returning false.\n   *\n   * @return <code>true</code> if this thread has been interrupted; <code>false</code> otherwise.\n   */\n  public static boolean isInteruppted() {\n    return Threads.isInteruppted();\n  }\n\n  /** Prints the java stack trace of the current thread. */\n  public static void jstack() {\n    Threads.jstack(2, -1);\n  }\n\n  /**\n   * Prints the java stack trace of the current thread. But, at most given number of frames.\n   *\n   * @param numFrames number of frames to be printed. When this is negative all frames are printed.\n   */\n  public static void jstack(int numFrames) {\n    Threads.jstack(2, numFrames);\n  }\n\n  /** Prints Java stack traces of all the Java threads. */\n  public static void jstackAll() {\n    Threads.jstackAll(2, -1);\n  }\n\n  /**\n   * Prints Java stack traces of all the Java threads. But, at most given number of frames.\n   *\n   * @param numFrames number of frames to be printed. When this is negative all frames are printed.\n   */\n  public static void jstackAll(int numFrames) {\n    Threads.jstackAll(2, numFrames);\n  }\n\n  /**\n   * Returns the stack trace of current thread as a String.\n   *\n   * @return the stack trace as a String.\n   */\n  public static String jstackStr() {\n    return Threads.jstackStr(2, -1);\n  }\n\n  /**\n   * Returns the stack trace of the current thread as a String but includes at most the given number\n   * of frames.\n   *\n   * @param numFrames number of frames to be included. When this is negative all frames are\n   *     included.\n   * @return the stack trace as a String.\n   */\n  public static String jstackStr(int numFrames) {\n    return Threads.jstackStr(2, numFrames);\n  }\n\n  /**\n   * Returns the stack traces of all Java threads as a String.\n   *\n   * @return the stack traces as a String.\n   */\n  public static String jstackAllStr() {\n    return Threads.jstackAllStr();\n  }\n\n  /**\n   * Returns at most given number of frames in stack traces of all threads as a String.\n   *\n   * @param numFrames number of frames to be included. When this is negative all frames are\n   *     included.\n   * @return the stack traces as a String.\n   */\n  public static String jstackAllStr(int numFrames) {\n    return Threads.jstackAllStr(numFrames);\n  }\n\n  /**\n   * Prints the stack trace of the given exception object.\n   *\n   * @param exception throwable for which stack trace is printed.\n   */\n  public static void jstack(Throwable exception) {\n    Threads.jstack(exception);\n  }\n\n  /**\n   * Prints the stack trace of the given exception object. But, prints atmost given number of\n   * frames.\n   *\n   * @param exception throwable for which stack trace is printed.\n   * @param numFrames maximum number of frames to be printed.\n   */\n  public static void jstack(Throwable exception, int numFrames) {\n    Threads.jstack(exception, numFrames);\n  }\n\n  /**\n   * Returns the stack trace of given exception object as a String.\n   *\n   * @param exception the throwable for which stack trace is returned.\n   */\n  public static String jstackStr(Throwable exception) {\n    return Threads.jstackStr(exception);\n  }\n\n  /**\n   * Returns stack trace of given exception object as a String.\n   *\n   * @param exception throwable for which stack trace is returned.\n   * @param numFrames maximum number of frames to be returned.\n   */\n  public static String jstackStr(Throwable exception, int numFrames) {\n    return Threads.jstackStr(exception, numFrames);\n  }\n\n  /**\n   * Returns a reference to the currently executing thread object.\n   *\n   * @return the currently executing thread.\n   */\n  public static Thread currentThread() {\n    return Threads.currentThread();\n  }\n\n  /**\n   * Returns the identifier of the given Thread. The thread ID is a positive <tt>long</tt> number\n   * generated when the given thread was created. The thread ID is unique and remains unchanged\n   * during its lifetime. When a thread is terminated, the thread ID may be reused.\n   */\n  public static long threadId(Thread thread) {\n    return Threads.threadId(thread);\n  }\n\n  /**\n   * Returns the state of the given thread. This method is designed for use in monitoring of the\n   * system state, not for synchronization control.\n   */\n  public static Thread.State threadState(Thread thread) {\n    return Threads.threadState(thread);\n  }\n\n  /**\n   * Returns <tt>true</tt> if and only if the current thread holds the monitor lock on the specified\n   * object.\n   *\n   * <p>This method is designed to allow a program to assert that the current thread already holds a\n   * specified lock:\n   *\n   * <pre>\n   *     assert Thread.holdsLock(obj);\n   * </pre>\n   *\n   * @param obj the object on which to test lock ownership\n   * @return <tt>true</tt> if the current thread holds the monitor lock on the specified object.\n   * @throws NullPointerException if obj is <tt>null</tt>\n   */\n  public static boolean holdsLock(Object obj) {\n    return Threads.holdsLock(obj);\n  }\n\n  /** Prints the Java level deadlocks detected (if any). */\n  public static void deadlocks() {\n    Threads.deadlocks();\n  }\n\n  /**\n   * Prints deadlocks detected (if any). Optionally prints stack trace of the deadlocked threads.\n   *\n   * @param stackTrace boolean flag to specify whether to print stack traces of deadlocked threads\n   *     or not.\n   */\n  public static void deadlocks(boolean stackTrace) {\n    Threads.deadlocks(stackTrace);\n  }\n\n  /**\n   * Returns the name of the given thread.\n   *\n   * @param thread thread whose name is returned\n   */\n  public static String name(Thread thread) {\n    return Threads.name(thread);\n  }\n\n  // class loader access\n\n  /**\n   * Returns the class loader for the given class. Some implementations may use null to represent\n   * the bootstrap class loader. This method will return null in such implementations if this class\n   * was loaded by the bootstrap class loader.\n   *\n   * @param clazz the Class for which the class loader is returned\n   */\n  public static ClassLoader loader(Class<?> clazz) {\n    return clazz.getClassLoader();\n  }\n\n  /**\n   * Returns the parent class loader of the given loader. Some implementations may use <tt>null</tt>\n   * to represent the bootstrap class loader. This method will return <tt>null</tt> in such\n   * implementations if this class loader's parent is the bootstrap class loader.\n   *\n   * @param loader the loader for which the parent loader is returned\n   * @return The parent <tt>ClassLoader</tt>\n   */\n  public static ClassLoader parentLoader(ClassLoader loader) {\n    return loader.getParent();\n  }\n\n  // java.lang.Object methods\n\n  /**\n   * Returns a string representation of the object. In general, the <code>toString</code> method\n   * returns a string that \"textually represents\" this object. The result should be a concise but\n   * informative representation that is easy for a person to read. For bootstrap classes, returns\n   * the result of calling Object.toString() override. For non-bootstrap classes, default toString()\n   * value [className@hashCode] is returned.\n   *\n   * @param obj the object whose string representation is returned\n   * @return a string representation of the given object.\n   */\n  public static String str(Object obj) {\n    return Strings.str(obj);\n  }\n\n  public static String str(Object[] array) {\n    return Strings.str(array);\n  }\n\n  /**\n   * Returns identity string of the form class-name@identity-hash\n   *\n   * @param obj object for which identity string is returned\n   * @return identity string\n   */\n  public static String identityStr(Object obj) {\n    int hashCode = java.lang.System.identityHashCode(obj);\n    return obj.getClass().getName() + \"@\" + Integer.toHexString(hashCode);\n  }\n\n  /**\n   * Returns a hash code value for the object. This method is supported for the benefit of\n   * hashtables such as those provided by <code>java.util.Hashtable</code>. For bootstrap classes,\n   * returns the result of calling Object.hashCode() override. For non-bootstrap classes, the\n   * identity hash code is returned.\n   *\n   * @param obj the Object whose hash code is returned.\n   * @return a hash code value for the given object.\n   */\n  public static int hash(Object obj) {\n    if (obj.getClass().getClassLoader() == null) {\n      return obj.hashCode();\n    } else {\n      return java.lang.System.identityHashCode(obj);\n    }\n  }\n\n  /**\n   * Returns the same hash code for the given object as would be returned by the default method\n   * hashCode(), whether or not the given object's class overrides hashCode(). The hash code for the\n   * null reference is zero.\n   *\n   * @param obj object for which the hashCode is to be calculated\n   * @return the hashCode\n   */\n  public static int identityHashCode(Object obj) {\n    return java.lang.System.identityHashCode(obj);\n  }\n\n  /**\n   * Indicates whether two given objects are \"equal to\" one another. For bootstrap classes, returns\n   * the result of calling Object.equals() override. For non-bootstrap classes, the reference\n   * identity comparison is done.\n   *\n   * @param obj1 first object to compare equality\n   * @param obj2 second object to compare equality\n   * @return <code>true</code> if the given objects are equal; <code>false</code> otherwise.\n   */\n  public static boolean compare(Object obj1, Object obj2) {\n    return BTraceRuntime.compare(obj1, obj2);\n  }\n\n  // reflection\n\n  /**\n   * Returns the runtime class of the given Object.\n   *\n   * @param obj the Object whose Class is returned\n   * @return the Class object of given object\n   */\n  public static Class<?> classOf(Object obj) {\n    return Reflective.classOf(obj);\n  }\n\n  /**\n   * Checks whether the provided object is an instance of the named class. <cite>Note: this method\n   * can be rather CPU intensive, use with caution</cite>\n   *\n   * @param obj the object to check\n   * @param className the class name; as a special case {@code void} can be provided to check\n   *     whether the instance is a void value wrapper - {@linkplain AnyType#VOID}\n   * @return {@code true} if the object can be assigned to an instance of 'className' type\n   * @since 1.3.5\n   */\n  public static boolean instanceOf(Object obj, String className) {\n    return BTraceRuntime.instanceOf(obj, className);\n  }\n\n  /**\n   * Returns the Class object representing the class or interface that declares the field\n   * represented by the given Field object.\n   *\n   * @param field whose declaring Class is returned\n   */\n  public static Class<?> declaringClass(Field field) {\n    return Reflective.declaringClass(field);\n  }\n\n  /** Returns the name of the given Class object. */\n  public static String name(Class<?> clazz) {\n    return Reflective.name(clazz);\n  }\n\n  /**\n   * Returns the name of the Field object.\n   *\n   * @param field Field for which name is returned\n   * @return name of the given field\n   */\n  public static String name(Field field) {\n    return Reflective.name(field);\n  }\n\n  /**\n   * Returns the type of the Field object.\n   *\n   * @param field Field for which type is returned\n   * @return type of the given field\n   */\n  public static Class<?> type(Field field) {\n    return Reflective.type(field);\n  }\n\n  /** Returns the access flags of the given Class. */\n  public static int accessFlags(Class<?> clazz) {\n    return Reflective.accessFlags(clazz);\n  }\n\n  /** Returns the access flags of the given Field. */\n  public static int accessFlags(Field field) {\n    return Reflective.accessFlags(field);\n  }\n\n  /** Returns the current context class loader */\n  public static ClassLoader contextClassLoader() {\n    return Reflective.contextClassLoader();\n  }\n\n  // get Class of the given name\n\n  /** Returns Class object for given class name. */\n  public static Class classForName(String name) {\n    return Reflective.classForName(name);\n  }\n\n  /** Returns the Class for the given class name using the given class loader. */\n  public static Class classForName(String name, ClassLoader cl) {\n    return Reflective.classForName(name, cl);\n  }\n\n  /**\n   * Determines if the class or interface represented by the first <code>Class</code> object is\n   * either the same as, or is a superclass or superinterface of, the class or interface represented\n   * by the second <code>Class</code> parameter. It returns <code>true</code> if so; otherwise it\n   * returns <code>false</code>.\n   */\n  public static boolean isAssignableFrom(Class<?> a, Class<?> b) {\n    return Reflective.isAssignableFrom(a, b);\n  }\n\n  /**\n   * Determines if the specified <code>Object</code> is assignment-compatible with the object\n   * represented by the specified <code>Class</code>. This method is the dynamic equivalent of the\n   * Java language <code>instanceof</code> operator. The method returns <code>true</code> if the\n   * specified <code>Object</code> argument is non-null and can be cast to the reference type\n   * represented by this <code>Class</code> object without raising a <code>ClassCastException.\n   * </code> It returns <code>false</code> otherwise.\n   *\n   * @param clazz the class that is checked.\n   * @param obj the object to check.\n   * @return true if <code>obj</code> is an instance of the given class.\n   */\n  public static boolean isInstance(Class<?> clazz, Object obj) {\n    return Reflective.isInstance(clazz, obj);\n  }\n\n  /**\n   * Returns the <code>Class</code> representing the superclass of the entity (class, interface,\n   * primitive type or void) represented by the given <code>Class</code>. If the given <code>Class\n   * </code> represents either the <code>Object</code> class, an interface, a primitive type, or\n   * void, then null is returned. If the given object represents an array class then the <code>Class\n   * </code> object representing the <code>Object</code> class is returned.\n   *\n   * @param clazz the Class whose super class is returned.\n   * @return the superclass of the class represented by the given object.\n   */\n  public static Class<?> getSuperclass(Class<?> clazz) {\n    return Reflective.getSuperclass(clazz);\n  }\n\n  /**\n   * Determines if the specified <code>Class</code> object represents an interface type.\n   *\n   * @param clazz the Class object to check.\n   * @return <code>true</code> if the Class represents an interface; <code>false</code> otherwise.\n   */\n  public static boolean isInterface(Class<?> clazz) {\n    return Reflective.isInterface(clazz);\n  }\n\n  /**\n   * Determines if the given <code>Class</code> object represents an array class.\n   *\n   * @param clazz Class object to check.\n   * @return <code>true</code> if the given object represents an array class; <code>false</code>\n   *     otherwise.\n   */\n  public static boolean isArray(Class<?> clazz) {\n    return Reflective.isArray(clazz);\n  }\n\n  /** Returns whether the given Class represent primitive type or not. */\n  public static boolean isPrimitive(Class<?> clazz) {\n    return Reflective.isPrimitive(clazz);\n  }\n\n  /** returns component type of an array Class. */\n  public static Class<?> getComponentType(Class<?> clazz) {\n    return Reflective.getComponentType(clazz);\n  }\n\n  // Accessing fields by reflection\n\n  /**\n   * Returns a <code>Field</code> object that reflects the specified declared field of the class or\n   * interface represented by the given <code>Class</code> object. The <code>name</code> parameter\n   * is a <code>String</code> that specifies the simple name of the desired field. Returns <code>\n   * null</code> on not finding field if throwException parameter is <code>false</code>. Else throws\n   * a <code>RuntimeException</code> when field is not found.\n   *\n   * @param clazz Class whose field is returned\n   * @param name the name of the field\n   * @param throwException whether to throw exception on failing to find field or not\n   * @return the <code>Field</code> object for the specified field in this class\n   */\n  public static Field field(Class<?> clazz, String name, boolean throwException) {\n    return Reflective.field(clazz, name, throwException);\n  }\n\n  /**\n   * Returns a <code>Field</code> object that reflects the specified declared field of the class or\n   * interface represented by the given <code>Class</code> object. The <code>name</code> parameter\n   * is a <code>String</code> that specifies the simple name of the desired field. Throws a <code>\n   * RuntimeException</code> when field is not found.\n   *\n   * @param clazz Class whose field is returned\n   * @param name the name of the field\n   * @return the <code>Field</code> object for the specified field in this class\n   */\n  public static Field field(Class<?> clazz, String name) {\n    return Reflective.field(clazz, name);\n  }\n\n  /**\n   * Returns a <code>Field</code> object that reflects the specified declared field of the class or\n   * interface represented by the given <code>Class</code> object. The <code>name</code> parameter\n   * is a <code>String</code> that specifies the simple name of the desired field. Returns <code>\n   * null</code> on not finding field if throwException parameter is <code>false</code>. Else throws\n   * a <code>RuntimeException</code> when field is not found.\n   *\n   * @param clazz Class whose field is returned\n   * @param name the name of the field\n   * @param throwException whether to throw exception on failing to find field or not\n   * @return the <code>Field</code> object for the specified field in this class\n   */\n  public static Field field(String clazz, String name, boolean throwException) {\n    ClassLoader callerLoader = BTraceRuntime.getCallerClassloader(STACK_DEC);\n    return Reflective.field(classForName(clazz, callerLoader), name, throwException);\n  }\n\n  /**\n   * Returns a <code>Field</code> object that reflects the specified declared field of the class or\n   * interface represented by the given <code>Class</code> object. The <code>name</code> parameter\n   * is a <code>String</code> that specifies the simple name of the desired field. Throws a <code>\n   * RuntimeException</code> when field is not found.\n   *\n   * @param clazz Class whose field is returned\n   * @param name the name of the field\n   * @return the <code>Field</code> object for the specified field in this class\n   */\n  public static Field field(String clazz, String name) {\n    ClassLoader callerLoader = BTraceRuntime.getCallerClassloader(STACK_DEC);\n    return Reflective.field(classForName(clazz, callerLoader), name);\n  }\n\n  // field value get methods\n\n  /**\n   * Gets the value of a static <code>byte</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @return the value of the <code>byte</code> field\n   */\n  public static byte getByte(Field field) {\n    return Reflective.getByte(field);\n  }\n\n  /**\n   * Gets the value of an instance <code>byte</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @param obj the object to extract the <code>byte</code> value from\n   * @return the value of the <code>byte</code> field\n   */\n  public static byte getByte(Field field, Object obj) {\n    return Reflective.getByte(field, obj);\n  }\n\n  /**\n   * Gets the value of a static <code>short</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @return the value of the <code>short</code> field\n   */\n  public static short getShort(Field field) {\n    return Reflective.getShort(field);\n  }\n\n  /**\n   * Gets the value of an instance <code>short</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @param obj the object to extract the <code>short</code> value from\n   * @return the value of the <code>short</code> field\n   */\n  public static short getShort(Field field, Object obj) {\n    return Reflective.getShort(field, obj);\n  }\n\n  /**\n   * Gets the value of a static <code>int</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @return the value of the <code>int</code> field\n   */\n  public static int getInt(Field field) {\n    return Reflective.getInt(field);\n  }\n\n  /**\n   * Gets the value of an instance <code>int</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @param obj the object to extract the <code>int</code> value from\n   * @return the value of the <code>int</code> field\n   */\n  public static int getInt(Field field, Object obj) {\n    return Reflective.getInt(field, obj);\n  }\n\n  /**\n   * Gets the value of a static <code>long</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @return the value of the <code>long</code> field\n   */\n  public static long getLong(Field field) {\n    return Reflective.getLong(field);\n  }\n\n  /**\n   * Gets the value of an instance <code>long</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @param obj the object to extract the <code>long</code> value from\n   * @return the value of the <code>long</code> field\n   */\n  public static long getLong(Field field, Object obj) {\n    return Reflective.getLong(field, obj);\n  }\n\n  /**\n   * Gets the value of a static <code>float</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @return the value of the <code>float</code> field\n   */\n  public static float getFloat(Field field) {\n    return Reflective.getFloat(field);\n  }\n\n  /**\n   * Gets the value of an instance <code>float</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @param obj the object to extract the <code>float</code> value from\n   * @return the value of the <code>float</code> field\n   */\n  public static float getFloat(Field field, Object obj) {\n    return Reflective.getFloat(field, obj);\n  }\n\n  /**\n   * Gets the value of a static <code>double</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @return the value of the <code>double</code> field\n   */\n  public static double getDouble(Field field) {\n    return Reflective.getDouble(field);\n  }\n\n  /**\n   * Gets the value of an instance <code>double</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @param obj the object to extract the <code>double</code> value from\n   * @return the value of the <code>double</code> field\n   */\n  public static double getDouble(Field field, Object obj) {\n    return Reflective.getDouble(field, obj);\n  }\n\n  /**\n   * Gets the value of a static <code>boolean</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @return the value of the <code>boolean</code> field\n   */\n  public static boolean getBoolean(Field field) {\n    return Reflective.getBoolean(field);\n  }\n\n  /**\n   * Gets the value of an instance <code>boolean</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @param obj the object to extract the <code>boolean</code> value from\n   * @return the value of the <code>boolean</code> field\n   */\n  public static boolean getBoolean(Field field, Object obj) {\n    return Reflective.getBoolean(field, obj);\n  }\n\n  /**\n   * Gets the value of a static <code>char</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @return the value of the <code>char</code> field\n   */\n  public static char getChar(Field field) {\n    return Reflective.getChar(field);\n  }\n\n  /**\n   * Gets the value of an instance <code>char</code> field.\n   *\n   * @param field Field object whose value is returned.\n   * @param obj the object to extract the <code>char</code> value from\n   * @return the value of the <code>char</code> field\n   */\n  public static char getChar(Field field, Object obj) {\n    return Reflective.getChar(field, obj);\n  }\n\n  /**\n   * Gets the value of a static reference field.\n   *\n   * @param field Field object whose value is returned.\n   * @return the value of the reference field\n   */\n  public static Object get(Field field) {\n    return Reflective.get(field);\n  }\n\n  /**\n   * Gets the value of an instance reference field.\n   *\n   * @param field Field object whose value is returned.\n   * @param obj the object to extract the reference value from\n   * @return the value of the reference field\n   */\n  public static Object get(Field field, Object obj) {\n    return Reflective.get(field, obj);\n  }\n\n  // weak, soft references\n\n  /**\n   * Creates and returns a weak reference to the given object.\n   *\n   * @param obj object for which a weak reference is created.\n   * @return a weak reference to the given object.\n   */\n  public static WeakReference weakRef(Object obj) {\n    return References.weakRef(obj);\n  }\n\n  /**\n   * Creates and returns a soft reference to the given object.\n   *\n   * @param obj object for which a soft reference is created.\n   * @return a soft reference to the given object.\n   */\n  public static SoftReference softRef(Object obj) {\n    return References.softRef(obj);\n  }\n\n  /**\n   * Returns the given reference object's referent. If the reference object has been cleared, either\n   * by the program or by the garbage collector, then this method returns <code>null</code>.\n   *\n   * @param ref reference object whose referent is returned.\n   * @return The object to which the reference refers, or <code>null</code> if the reference object\n   *     has been cleared.\n   */\n  public static Object deref(Reference ref) {\n    return References.deref(ref);\n  }\n\n  // probe point access\n\n  /**\n   * Returns the Class object of the currently probed (or traced) class.\n   *\n   * @deprecated Since 1.1. Use {@linkplain ProbeClassName} and {@linkplain Self} annotations\n   *     instead\n   */\n  @Deprecated\n  public static Class<?> probeClass() {\n    return BTraceRuntime.getCallerClass(STACK_DEC);\n  }\n\n  /**\n   * Returns the currently probed method's name.\n   *\n   * @deprecated Since 1.1. Use {@linkplain ProbeMethodName} annotation instead\n   */\n  @Deprecated\n  public static String probeMethod() {\n    StackTraceElement[] stack = Thread.currentThread().getStackTrace();\n    if (stack.length >= 4) {\n      return stack[3].getMethodName();\n    } else {\n      return null;\n    }\n  }\n\n  /** Returns the currently probed source line number (if available). */\n  public static int probeLine() {\n    StackTraceElement[] stack = Thread.currentThread().getStackTrace();\n    if (stack.length >= 4) {\n      return stack[3].getLineNumber();\n    } else {\n      return -1;\n    }\n  }\n\n  // printing values\n\n  /**\n   * Prints the given Map.\n   *\n   * @param map Map that is printed.\n   */\n  public static void printMap(Map map) {\n    BTraceRuntime.printMap(map);\n  }\n\n  /**\n   * Prints the given Map.\n   *\n   * @param name - the name of the map\n   * @param data - the map data\n   */\n  public static void printStringMap(String name, Map<String, String> data) {\n    BTraceRuntime.printStringMap(name, data);\n  }\n\n  /**\n   * Prints the given Map.\n   *\n   * @param name - the name of the map\n   * @param data - the map data\n   */\n  public static void printNumberMap(String name, Map<String, ? extends Number> data) {\n    BTraceRuntime.printNumberMap(name, data);\n  }\n\n  /**\n   * Prints a number.\n   *\n   * @param name - name of the number data\n   * @param value - value of the numerical data\n   */\n  public static void printNumber(String name, Number value) {\n    BTraceRuntime.printNumber(name, value);\n  }\n\n  /** Prints the elements of the given array as comma separated line bounded by '[' and ']'. */\n  public static void printArray(Object[] array) {\n    StringBuilder buf = new StringBuilder();\n    buf.append('[');\n    for (Object obj : array) {\n      buf.append(Strings.str(obj));\n      buf.append(\", \");\n    }\n    buf.append(']');\n    println(buf.toString());\n  }\n\n  /**\n   * Print all instance fields of an object as name-value pairs. Includes the inherited fields as\n   * well.\n   *\n   * @param obj Object whose fields are printed.\n   */\n  public static void printFields(Object obj) {\n    Reflective.printFields(obj, false);\n  }\n\n  /**\n   * Print all instance fields of an object as name-value pairs. Includes the inherited fields as\n   * well. Optionally, prints name of the declaring class before each field - so that if same named\n   * field in super class chain may be disambiguated.\n   *\n   * @param obj Object whose fields are printed.\n   * @param classNamePrefix flag to tell whether to prefix field names names by class name or not.\n   */\n  public static void printFields(Object obj, boolean classNamePrefix) {\n    Reflective.printFields(obj, classNamePrefix);\n  }\n\n  /**\n   * Print all static fields of the class as name-value pairs. Includes the inherited fields as\n   * well.\n   *\n   * @param clazz Class whose static fields are printed.\n   */\n  public static void printStaticFields(Class<?> clazz) {\n    Reflective.printStaticFields(clazz, false);\n  }\n\n  /**\n   * Print all static fields of the class as name-value pairs. Includes the inherited fields as\n   * well. Optionally, prints name of the declaring class before each field - so that if same named\n   * field in super class chain may be disambiguated.\n   *\n   * @param clazz Class whose static fields are printed.\n   * @param classNamePrefix flag to tell whether to prefix field names names by class name or not.\n   */\n  public static void printStaticFields(Class<?> clazz, boolean classNamePrefix) {\n    Reflective.printStaticFields(clazz, classNamePrefix);\n  }\n\n  // various print methods\n  public static void print(Object obj) {\n    BTraceRuntime.print(Strings.str(obj));\n  }\n\n  /**\n   * Prints a boolean value. The string produced by <code>{@link\n   * java.lang.String#valueOf(boolean)}</code> is sent to BTrace client for \"printing\".\n   *\n   * @param b The <code>boolean</code> to be printed\n   */\n  public static void print(boolean b) {\n    print(Boolean.valueOf(b));\n  }\n\n  /**\n   * Prints a character. The string produced by <code>{@link\n   * java.lang.Character#valueOf(char)}</code> is sent to BTrace client for \"printing\".\n   *\n   * @param c The <code>char</code> to be printed\n   */\n  public static void print(char c) {\n    print(Character.valueOf(c));\n  }\n\n  /**\n   * Prints an integer. The string produced by <code>{@link\n   * java.lang.String#valueOf(int)}</code> is sent to BTrace client for \"printing\".\n   *\n   * @param i The <code>int</code> to be printed\n   * @see java.lang.Integer#toString(int)\n   */\n  public static void print(int i) {\n    print(Integer.valueOf(i));\n  }\n\n  /**\n   * Prints a long integer. The string produced by <code>{@link\n   * java.lang.String#valueOf(long)}</code> is sent to BTrace client for \"printing\".\n   *\n   * @param l The <code>long</code> to be printed\n   * @see java.lang.Long#toString(long)\n   */\n  public static void print(long l) {\n    print(Long.valueOf(l));\n  }\n\n  /**\n   * Prints a floating-point number. The string produced by <code>{@link\n   * java.lang.String#valueOf(float)}</code> is sent to BTrace client for \"printing\".\n   *\n   * @param f The <code>float</code> to be printed\n   * @see java.lang.Float#toString(float)\n   */\n  public static void print(float f) {\n    print(Float.valueOf(f));\n  }\n\n  /**\n   * Prints a double-precision floating-point number. The string produced by <code>\n   * {@link java.lang.String#valueOf(double)}</code> is sent to BTrace client for \"printing\".\n   *\n   * @param d The <code>double</code> to be printed\n   * @see java.lang.Double#toString(double)\n   */\n  public static void print(double d) {\n    print(Double.valueOf(d));\n  }\n\n  /** Prints the given object and then prints a newline */\n  public static void println(Object obj) {\n    BTraceRuntime.println(Strings.str(obj));\n  }\n\n  /**\n   * Prints a boolean and then terminate the line. This method behaves as though it invokes <code>\n   * {@link #print(boolean)}</code> and then <code>{@link #println()}</code>.\n   *\n   * @param b The <code>boolean</code> to be printed\n   */\n  public static void println(boolean b) {\n    println(Boolean.valueOf(b));\n  }\n\n  /**\n   * Prints a character and then terminate the line. This method behaves as though it invokes <code>\n   * {@link #print(char)}</code> and then <code>{@link #println()}</code>.\n   *\n   * @param c The <code>char</code> to be printed.\n   */\n  public static void println(char c) {\n    println(Character.valueOf(c));\n  }\n\n  /**\n   * Prints an integer and then terminate the line. This method behaves as though it invokes <code>\n   * {@link #print(int)}</code> and then <code>{@link #println()}</code>.\n   *\n   * @param i The <code>int</code> to be printed.\n   */\n  public static void println(int i) {\n    println(Integer.valueOf(i));\n  }\n\n  /**\n   * Prints a long and then terminate the line. This method behaves as though it invokes <code>\n   * {@link #print(long)}</code> and then <code>{@link #println()}</code>.\n   *\n   * @param l a The <code>long</code> to be printed.\n   */\n  public static void println(long l) {\n    println(Long.valueOf(l));\n  }\n\n  /**\n   * Prints a float and then terminate the line. This method behaves as though it invokes <code>\n   * {@link #print(float)}</code> and then <code>{@link #println()}</code>.\n   *\n   * @param f The <code>float</code> to be printed.\n   */\n  public static void println(float f) {\n    println(Float.valueOf(f));\n  }\n\n  /**\n   * Prints a double and then terminate the line. This method behaves as though it invokes <code>\n   * {@link #print(double)}</code> and then <code>{@link #println()}</code>.\n   *\n   * @param d The <code>double</code> to be printed.\n   */\n  public static void println(double d) {\n    println(Double.valueOf(d));\n  }\n\n  /**\n   * Terminates the current line by writing the line separator string. The line separator string is\n   * defined by the system property <code>line.separator</code>, and is not necessarily a single\n   * newline character (<code>'\\n'</code>).\n   */\n  public static void println() {\n    BTraceRuntime.println();\n  }\n\n  /**\n   * Returns the start time of the Java virtual machine in milliseconds. This method returns the\n   * approximate time when the Java virtual machine started.\n   *\n   * @return start time of the Java virtual machine in milliseconds.\n   */\n  public static long vmStartTime() {\n    return Sys.VM.vmStartTime();\n  }\n\n  /**\n   * Returns the uptime of the Java virtual machine in milliseconds.\n   *\n   * @return uptime of the Java virtual machine in milliseconds.\n   */\n  public static long vmUptime() {\n    return Sys.VM.vmUptime();\n  }\n\n  /**\n   * Returns the current time in milliseconds. Note that while the unit of time of the return value\n   * is a millisecond, the granularity of the value depends on the underlying operating system and\n   * may be larger. For example, many operating systems measure time in units of tens of\n   * milliseconds.\n   *\n   * @return the difference, measured in milliseconds, between the current time and midnight,\n   *     January 1, 1970 UTC.\n   */\n  public static long timeMillis() {\n    return Time.millis();\n  }\n\n  /**\n   * Returns the current value of the most precise available system timer, in nanoseconds.\n   *\n   * <p>This method can only be used to measure elapsed time and is not related to any other notion\n   * of system or wall-clock time. The value returned represents nanoseconds since some fixed but\n   * arbitrary time (perhaps in the future, so values may be negative). This method provides\n   * nanosecond precision, but not necessarily nanosecond accuracy. No guarantees are made about how\n   * frequently values change. Differences in successive calls that span greater than approximately\n   * 292 years (2<sup>63</sup> nanoseconds) will not accurately compute elapsed time due to\n   * numerical overflow.\n   *\n   * @return The current value of the system timer, in nanoseconds.\n   */\n  public static long timeNanos() {\n    return Time.nanos();\n  }\n\n  /**\n   * Generates a string getTimestamp (current date&amp;time)\n   *\n   * @param format The format to be used - see {@linkplain SimpleDateFormat}\n   * @return Returns a string representing current date&amp;time\n   * @since 1.1\n   */\n  public static String timestamp(String format) {\n    return Time.timestamp(format);\n  }\n\n  /**\n   * Generates a string getTimestamp (current date&amp;time) in the default system format\n   *\n   * @return Returns a string representing current date&amp;time\n   * @since 1.1\n   */\n  public static String timestamp() {\n    return Time.timestamp();\n  }\n\n  // String utilities\n  public static boolean startsWith(String s, String start) {\n    return Strings.startsWith(s, start);\n  }\n\n  public static boolean endsWith(String s, String end) {\n    return Strings.endsWith(s, end);\n  }\n\n  /**\n   * This is synonym to \"concat\".\n   *\n   * @see #concat(String, String)\n   */\n  public static String strcat(String str1, String str2) {\n    return Strings.strcat(str1, str2);\n  }\n\n  /** Concatenates the specified strings together. */\n  public static String concat(String str1, String str2) {\n    return Strings.concat(str1, str2);\n  }\n\n  /**\n   * Compares two strings lexicographically. The comparison is based on the Unicode value of each\n   * character in the strings. The character sequence represented by the first <code>String</code>\n   * object is compared lexicographically to the character sequence represented by the second\n   * string. The result is a negative integer if the first <code>String</code> object\n   * lexicographically precedes the second string. The result is a positive integer if the first\n   * <code>String</code> object lexicographically follows the second string. The result is zero if\n   * the strings are equal; <code>compareTo</code> returns <code>0</code> exactly when the {@link\n   * String#equals(Object)} method would return <code>true</code>.\n   */\n  public static int compareTo(String str1, String str2) {\n    return Strings.compareTo(str1, str2);\n  }\n\n  /**\n   * This is synonym to \"compareTo\" method.\n   *\n   * @see #compareTo\n   */\n  public static int strcmp(String str1, String str2) {\n    return Strings.strcmp(str1, str2);\n  }\n\n  /**\n   * Compares two strings lexicographically, ignoring case differences. This method returns an\n   * integer whose sign is that of calling <code>compareTo</code> with normalized versions of the\n   * strings where case differences have been eliminated by calling <code>\n   * Character.toLowerCase(Character.toUpperCase(character))</code> on each character.\n   */\n  public static int compareToIgnoreCase(String str1, String str2) {\n    return Strings.compareToIgnoreCase(str1, str2);\n  }\n\n  /**\n   * This is synonym to \"compareToIgnoreCase\".\n   *\n   * @see #compareToIgnoreCase\n   */\n  public static int stricmp(String str1, String str2) {\n    return Strings.stricmp(str1, str2);\n  }\n\n  /** Find String within String */\n  public static int strstr(String str1, String str2) {\n    return Strings.strstr(str1, str2);\n  }\n\n  public static int indexOf(String str1, String str2) {\n    return Strings.indexOf(str1, str2);\n  }\n\n  public static int lastIndexOf(String str1, String str2) {\n    return Strings.lastIndexOf(str1, str2);\n  }\n\n  /** Substring */\n  public static String substr(String str, int start, int length) {\n    return Strings.substr(str, start, length);\n  }\n\n  public static String substr(String str, int start) {\n    return Strings.substr(str, start);\n  }\n\n  /**\n   * Returns the length of the given string. The length is equal to the number of <a\n   * href=\"Character.html#unicode\">Unicode code units</a> in the string.\n   *\n   * @param str String whose length is calculated.\n   * @return the length of the sequence of characters represented by this object.\n   */\n  public static int length(String str) {\n    return Strings.length(str);\n  }\n\n  /**\n   * This is synonym for \"length\".\n   *\n   * @see #length(String)\n   */\n  public static int strlen(String str) {\n    return Strings.strlen(str);\n  }\n\n  // regular expression matching\n\n  /**\n   * Compiles the given regular expression into a pattern.\n   *\n   * @param regex The expression to be compiled\n   * @throws PatternSyntaxException If the expression's syntax is invalid\n   */\n  public static Pattern regexp(String regex) {\n    return Strings.regexp(regex);\n  }\n\n  /**\n   * This is synonym for \"regexp\".\n   *\n   * @see #regexp(String)\n   */\n  public static Pattern pattern(String regex) {\n    return Strings.pattern(regex);\n  }\n\n  /**\n   * Compiles the given regular expression into a pattern with the given flags.\n   *\n   * @param regex The expression to be compiled\n   * @param flags Match flags, a bit mask that may include {@link Pattern#CASE_INSENSITIVE}, {@link\n   *     Pattern#MULTILINE}, {@link Pattern#DOTALL}, {@link Pattern#UNICODE_CASE}, {@link\n   *     Pattern#CANON_EQ}, {@link Pattern#UNIX_LINES}, {@link Pattern#LITERAL} and {@link\n   *     Pattern#COMMENTS}\n   * @throws IllegalArgumentException If bit values other than those corresponding to the defined\n   *     match flags are set in <tt>flags</tt>\n   * @throws PatternSyntaxException If the expression's syntax is invalid\n   */\n  public static Pattern regexp(String regex, int flags) {\n    return Strings.regexp(regex, flags);\n  }\n\n  /**\n   * This is synonym for \"regexp\".\n   *\n   * @see #regexp(String, int)\n   */\n  public static Pattern pattern(String regex, int flags) {\n    return Strings.pattern(regex, flags);\n  }\n\n  /**\n   * Matches the given (precompiled) regular expression and attempts to match the given input\n   * against it.\n   */\n  public static boolean matches(Pattern regex, String input) {\n    return Strings.matches(regex, input);\n  }\n\n  /**\n   * Compiles the given regular expression and attempts to match the given input against it.\n   *\n   * <p>An invocation of this convenience method of the form\n   *\n   * <blockquote>\n   *\n   * <pre>\n   * Pattern.matches(regex, input);</pre>\n   *\n   * </blockquote>\n   *\n   * <p>behaves in exactly the same way as the expression\n   *\n   * <blockquote>\n   *\n   * <pre>\n   * Pattern.compile(regex).matcher(input).matches()</pre>\n   *\n   * </blockquote>\n   *\n   * <p>If a pattern is to be used multiple times, compiling it once and reusing it will be more\n   * efficient than invoking this method each time.\n   *\n   * @param regex The expression to be compiled\n   * @param input The character sequence to be matched\n   * @throws PatternSyntaxException If the expression's syntax is invalid\n   */\n  public static boolean matches(String regex, String input) {\n    return Strings.matches(regex, input);\n  }\n\n  // Numbers utilities\n\n  /**\n   * Returns a <code>double</code> value with a positive sign, greater than or equal to <code>0.0\n   * </code> and less than <code>1.0</code>. Returned values are chosen pseudorandomly with\n   * (approximately) uniform distribution from that range.\n   */\n  public static double random() {\n    return Numbers.random();\n  }\n\n  /**\n   * Returns the natural logarithm (base <i>e</i>) of a <code>double</code> value. Special cases:\n   *\n   * <ul>\n   *   <li>If the argument is NaN or less than zero, then the result is NaN.\n   *   <li>If the argument is positive infinity, then the result is positive infinity.\n   *   <li>If the argument is positive zero or negative zero, then the result is negative infinity.\n   * </ul>\n   *\n   * <p>The computed result must be within 1 ulp of the exact result. Results must be\n   * semi-monotonic.\n   *\n   * @param a a value\n   * @return the value ln&nbsp;<code>a</code>, the natural logarithm of <code>a</code>.\n   */\n  public static strictfp double log(double a) {\n    return Numbers.log(a);\n  }\n\n  /**\n   * Returns the base 10 logarithm of a <code>double</code> value. Special cases:\n   *\n   * <ul>\n   *   <li>If the argument is NaN or less than zero, then the result is NaN.\n   *   <li>If the argument is positive infinity, then the result is positive infinity.\n   *   <li>If the argument is positive zero or negative zero, then the result is negative infinity.\n   *   <li>If the argument is equal to 10<sup><i>n</i></sup> for integer <i>n</i>, then the result\n   *       is <i>n</i>.\n   * </ul>\n   *\n   * <p>The computed result must be within 1 ulp of the exact result. Results must be\n   * semi-monotonic.\n   *\n   * @param a a value\n   * @return the base 10 logarithm of <code>a</code>.\n   */\n  public static strictfp double log10(double a) {\n    return Numbers.log10(a);\n  }\n\n  /**\n   * Returns Euler's number <i>e</i> raised to the power of a <code>double</code> value. Special\n   * cases:\n   *\n   * <ul>\n   *   <li>If the argument is NaN, the result is NaN.\n   *   <li>If the argument is positive infinity, then the result is positive infinity.\n   *   <li>If the argument is negative infinity, then the result is positive zero.\n   * </ul>\n   *\n   * <p>The computed result must be within 1 ulp of the exact result. Results must be\n   * semi-monotonic.\n   *\n   * @param a the exponent to raise <i>e</i> to.\n   * @return the value <i>e</i><sup><code>a</code></sup>, where <i>e</i> is the base of the natural\n   *     logarithms.\n   */\n  public static strictfp double exp(double a) {\n    return Numbers.exp(a);\n  }\n\n  /**\n   * Returns <code>true</code> if the specified number is a Not-a-Number (NaN) value, <code>false\n   * </code> otherwise.\n   *\n   * @param d the value to be tested.\n   * @return <code>true</code> if the value of the argument is NaN; <code>false</code> otherwise.\n   */\n  public static boolean isNaN(double d) {\n    return Numbers.isNaN(d);\n  }\n\n  /**\n   * Returns <code>true</code> if the specified number is a Not-a-Number (NaN) value, <code>false\n   * </code> otherwise.\n   *\n   * @param f the value to be tested.\n   * @return <code>true</code> if the value of the argument is NaN; <code>false</code> otherwise.\n   */\n  public static boolean isNaN(float f) {\n    return Numbers.isNaN(f);\n  }\n\n  /**\n   * Returns <code>true</code> if the specified number is infinitely large in magnitude, <code>false\n   * </code> otherwise.\n   *\n   * @param d the value to be tested.\n   * @return <code>true</code> if the value of the argument is positive infinity or negative\n   *     infinity; <code>false</code> otherwise.\n   */\n  public static boolean isInfinite(double d) {\n    return Numbers.isInfinite(d);\n  }\n\n  /**\n   * Returns <code>true</code> if the specified number is infinitely large in magnitude, <code>false\n   * </code> otherwise.\n   *\n   * @param f the value to be tested.\n   * @return <code>true</code> if the value of the argument is positive infinity or negative\n   *     infinity; <code>false</code> otherwise.\n   */\n  public static boolean isInfinite(float f) {\n    return Numbers.isInfinite(f);\n  }\n\n  // string parsing methods\n\n  /**\n   * Parses the string argument as a boolean. The <code>boolean</code> returned represents the value\n   * <code>true</code> if the string argument is not <code>null</code> and is equal, ignoring case,\n   * to the string {@code \"true\"}.\n   *\n   * <p>Example: {@code Boolean.parseBoolean(\"True\")} returns <tt>true</tt>.<br>\n   * Example: {@code Boolean.parseBoolean(\"yes\")} returns <tt>false</tt>.\n   *\n   * @param s the <code>String</code> containing the boolean representation to be parsed\n   * @return the boolean represented by the string argument\n   */\n  public static boolean parseBoolean(String s) {\n    return Numbers.parseBoolean(s);\n  }\n\n  /**\n   * Parses the string argument as a signed decimal <code>byte</code>. The characters in the string\n   * must all be decimal digits, except that the first character may be an ASCII minus sign <code>\n   * '-'</code> (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting <code>byte\n   * </code> value is returned.\n   *\n   * @param s a <code>String</code> containing the <code>byte</code> representation to be parsed\n   * @return the <code>byte</code> value represented by the argument in decimal\n   */\n  public static byte parseByte(String s) {\n    return Numbers.parseByte(s);\n  }\n\n  /**\n   * Parses the string argument as a signed decimal <code>short</code>. The characters in the string\n   * must all be decimal digits, except that the first character may be an ASCII minus sign <code>\n   * '-'</code> (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting <code>short\n   * </code> value is returned.\n   *\n   * @param s a <code>String</code> containing the <code>short</code> representation to be parsed\n   * @return the <code>short</code> value represented by the argument in decimal.\n   */\n  public static short parseShort(String s) {\n    return Numbers.parseShort(s);\n  }\n\n  /**\n   * Parses the string argument as a signed decimal integer. The characters in the string must all\n   * be decimal digits, except that the first character may be an ASCII minus sign <code>'-'</code>\n   * (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting integer value is\n   * returned.\n   *\n   * @param s a <code>String</code> containing the <code>int</code> representation to be parsed\n   * @return the integer value represented by the argument in decimal.\n   */\n  public static int parseInt(String s) {\n    return Numbers.parseInt(s);\n  }\n\n  /**\n   * Parses the string argument as a signed decimal <code>long</code>. The characters in the string\n   * must all be decimal digits, except that the first character may be an ASCII minus sign <code>\n   * '-'</code> (<code>&#92;u002D'</code>) to indicate a negative value. The resulting <code>long\n   * </code> value is returned.\n   *\n   * <p>Note that neither the character <code>L</code> (<code>'&#92;u004C'</code>) nor <code>l\n   * </code> (<code>'&#92;u006C'</code>) is permitted to appear at the end of the string as a type\n   * indicator, as would be permitted in Java programming language source code.\n   *\n   * @param s a <code>String</code> containing the <code>long</code> representation to be parsed\n   * @return the <code>long</code> represented by the argument in decimal.\n   */\n  public static long parseLong(String s) {\n    return Numbers.parseLong(s);\n  }\n\n  /**\n   * Returns a new <code>float</code> initialized to the value represented by the specified <code>\n   * String</code>, as performed by the <code>valueOf</code> method of class <code>Float</code>.\n   *\n   * @param s the string to be parsed.\n   * @return the <code>float</code> value represented by the string argument.\n   */\n  public static float parseFloat(String s) {\n    return Numbers.parseFloat(s);\n  }\n\n  /**\n   * Returns a new <code>double</code> initialized to the value represented by the specified <code>\n   * String</code>, as performed by the <code>valueOf</code> methcod of class <code>Double</code>.\n   *\n   * @param s the string to be parsed.\n   * @return the <code>double</code> value represented by the string argument.\n   */\n  public static double parseDouble(String s) {\n    return Numbers.parseDouble(s);\n  }\n\n  // boxing methods\n\n  /**\n   * Returns a <tt>Boolean</tt> instance representing the specified <tt>boolean</tt> value. If the\n   * specified <tt>boolean</tt> value is <tt>true</tt>, this method returns <tt>Boolean.TRUE</tt>;\n   * if it is <tt>false</tt>, this method returns <tt>Boolean.FALSE</tt>.\n   *\n   * @param b a boolean value.\n   * @return a <tt>Boolean</tt> instance representing <tt>b</tt>.\n   */\n  public static Boolean box(boolean b) {\n    return Numbers.box(b);\n  }\n\n  /**\n   * Returns a <tt>Character</tt> instance representing the specified <tt>char</tt> value.\n   *\n   * @param c a char value.\n   * @return a <tt>Character</tt> instance representing <tt>c</tt>.\n   */\n  public static Character box(char c) {\n    return Numbers.box(c);\n  }\n\n  /**\n   * Returns a <tt>Byte</tt> instance representing the specified <tt>byte</tt> value.\n   *\n   * @param b a byte value.\n   * @return a <tt>Byte</tt> instance representing <tt>b</tt>.\n   */\n  public static Byte box(byte b) {\n    return Numbers.box(b);\n  }\n\n  /**\n   * Returns a <tt>Short</tt> instance representing the specified <tt>short</tt> value.\n   *\n   * @param s a short value.\n   * @return a <tt>Short</tt> instance representing <tt>s</tt>.\n   */\n  public static Short box(short s) {\n    return Numbers.box(s);\n  }\n\n  /**\n   * Returns a <tt>Integer</tt> instance representing the specified <tt>int</tt> value.\n   *\n   * @param i an <code>int</code> value.\n   * @return a <tt>Integer</tt> instance representing <tt>i</tt>.\n   */\n  public static Integer box(int i) {\n    return Numbers.box(i);\n  }\n\n  /**\n   * Returns a <tt>Long</tt> instance representing the specified <tt>long</tt> value.\n   *\n   * @param l a long value.\n   * @return a <tt>Long</tt> instance representing <tt>l</tt>.\n   */\n  public static Long box(long l) {\n    return Numbers.box(l);\n  }\n\n  /**\n   * Returns a <tt>Float</tt> instance representing the specified <tt>float</tt> value.\n   *\n   * @param f a float value.\n   * @return a <tt>Float</tt> instance representing <tt>f</tt>.\n   */\n  public static Float box(float f) {\n    return Numbers.box(f);\n  }\n\n  /**\n   * Returns a <tt>Double</tt> instance representing the specified <tt>double</tt> value.\n   *\n   * @param d a double value.\n   * @return a <tt>Double</tt> instance representing <tt>d</tt>.\n   */\n  public static Double box(double d) {\n    return Numbers.box(d);\n  }\n\n  // unboxing methods\n\n  /**\n   * Returns the value of the given <tt>Boolean</tt> object as a boolean primitive.\n   *\n   * @param b the Boolean object whose value is returned.\n   * @return the primitive <code>boolean</code> value of the object.\n   */\n  public static boolean unbox(Boolean b) {\n    return Numbers.unbox(b);\n  }\n\n  /**\n   * Returns the value of the given <tt>Character</tt> object as a char primitive.\n   *\n   * @param ch the Character object whose value is returned.\n   * @return the primitive <code>char</code> value of the object.\n   */\n  public static char unbox(Character ch) {\n    return Numbers.unbox(ch);\n  }\n\n  /**\n   * Returns the value of the specified Byte as a <code>byte</code>.\n   *\n   * @param b Byte that is unboxed\n   * @return the byte value represented by the <code>Byte</code>.\n   */\n  public static byte unbox(Byte b) {\n    return Numbers.unbox(b);\n  }\n\n  /**\n   * Returns the short value represented by <code>Short</code>.\n   *\n   * @param s Short that is unboxed.\n   * @return the short value represented by the <code>Short</code>.\n   */\n  public static short unbox(Short s) {\n    return Numbers.unbox(s);\n  }\n\n  /**\n   * Returns the value of represented by <code>Integer</code>.\n   *\n   * @param i Integer that is unboxed.\n   * @return the int value represented by the <code>Integer</code>.\n   */\n  public static int unbox(Integer i) {\n    return Numbers.unbox(i);\n  }\n\n  /**\n   * Returns the long value represented by the specified <code>Long</code>.\n   *\n   * @param l Long to be unboxed.\n   * @return the long value represented by the <code>Long</code>.\n   */\n  public static long unbox(Long l) {\n    return Numbers.unbox(l);\n  }\n\n  /**\n   * Returns the float value represented by the specified <code>Float</code>.\n   *\n   * @param f Float to be unboxed.\n   * @return the float value represented by the <code>Float</code>.\n   */\n  public static float unbox(Float f) {\n    return Numbers.unbox(f);\n  }\n\n  /**\n   * Returns the double value represented by the specified <code>Double</code>.\n   *\n   * @param d Double to be unboxed.\n   */\n  public static double unbox(Double d) {\n    return Numbers.unbox(d);\n  }\n\n  // primitive types to String conversion\n\n  /**\n   * Returns a <tt>String</tt> object representing the specified boolean. If the specified boolean\n   * is <code>true</code>, then the string {@code \"true\"} will be returned, otherwise the string\n   * {@code \"false\"} will be returned.\n   *\n   * @param b the boolean to be converted\n   * @return the string representation of the specified <code>boolean</code>\n   */\n  public static String str(boolean b) {\n    return Strings.str(b);\n  }\n\n  /**\n   * Returns a <code>String</code> object representing the specified <code>char</code>. The result\n   * is a string of length 1 consisting solely of the specified <code>char</code>.\n   *\n   * @param c the <code>char</code> to be converted\n   * @return the string representation of the specified <code>char</code>\n   */\n  public static String str(char c) {\n    return Strings.str(c);\n  }\n\n  /**\n   * Returns a <code>String</code> object representing the specified integer. The argument is\n   * converted to signed decimal representation and returned as a string.\n   *\n   * @param i an integer to be converted.\n   * @return a string representation of the argument in base&nbsp;10.\n   */\n  public static String str(int i) {\n    return Strings.str(i);\n  }\n\n  /**\n   * Returns a string representation of the integer argument as an unsigned integer in base&nbsp;16.\n   *\n   * <p>The unsigned integer value is the argument plus 2<sup>32</sup> if the argument is negative;\n   * otherwise, it is equal to the argument. This value is converted to a string of ASCII digits in\n   * hexadecimal (base&nbsp;16) with no extra leading <code>0</code>s. If the unsigned magnitude is\n   * zero, it is represented by a single zero character <code>'0'</code> (<code>'&#92;u0030'</code>\n   * ); otherwise, the first character of the representation of the unsigned magnitude will not be\n   * the zero character. The following characters are used as hexadecimal digits:\n   *\n   * <blockquote>\n   *\n   * <pre>\n   * 0123456789abcdef\n   * </pre>\n   *\n   * </blockquote>\n   *\n   * These are the characters <code>'&#92;u0030'</code> through <code>'&#92;u0039'</code> and <code>\n   * '&#92;u0061'</code> through <code>'&#92;u0066'</code>.\n   *\n   * @param i an integer to be converted to a string.\n   * @return the string representation of the unsigned integer value represented by the argument in\n   *     hexadecimal (base&nbsp;16).\n   */\n  public static String toHexString(int i) {\n    return Strings.toHexString(i);\n  }\n\n  /**\n   * Returns a <code>String</code> object representing the specified <code>long</code>. The argument\n   * is converted to signed decimal representation and returned as a string.\n   *\n   * @param l a <code>long</code> to be converted.\n   * @return a string representation of the argument in base&nbsp;10.\n   */\n  public static String str(long l) {\n    return Strings.str(l);\n  }\n\n  /**\n   * Returns a string representation of the <code>long</code> argument as an unsigned integer in\n   * base&nbsp;16.\n   *\n   * <p>The unsigned <code>long</code> value is the argument plus 2<sup>64</sup> if the argument is\n   * negative; otherwise, it is equal to the argument. This value is converted to a string of ASCII\n   * digits in hexadecimal (base&nbsp;16) with no extra leading <code>0</code>s. If the unsigned\n   * magnitude is zero, it is represented by a single zero character <code>'0'</code> (<code>\n   * '&#92;u0030'</code>); otherwise, the first character of the representation of the unsigned\n   * magnitude will not be the zero character. The following characters are used as hexadecimal\n   * digits:\n   *\n   * <blockquote>\n   *\n   * <pre>\n   * 0123456789abcdef\n   * </pre>\n   *\n   * </blockquote>\n   *\n   * These are the characters <code>'&#92;u0030'</code> through <code>'&#92;u0039'</code> and <code>\n   * '&#92;u0061'</code> through <code>'&#92;u0066'</code>.\n   *\n   * @param l a <code>long</code> to be converted to a string.\n   * @return the string representation of the unsigned <code>long</code> value represented by the\n   *     argument in hexadecimal (base&nbsp;16).\n   */\n  public static String toHexString(long l) {\n    return Strings.toHexString(l);\n  }\n\n  /**\n   * Returns a string representation of the <code>float</code> argument. All characters mentioned\n   * below are ASCII characters.\n   *\n   * <ul>\n   *   <li>If the argument is NaN, the result is the string &quot;<code>NaN</code>&quot;.\n   *   <li>Otherwise, the result is a string that represents the sign and magnitude (absolute value)\n   *       of the argument. If the sign is negative, the first character of the result is '<code>-\n   *       </code>' (<code>'&#92;u002D'</code>); if the sign is positive, no sign character appears\n   *       in the result. As for the magnitude <i>m</i>:\n   *       <ul>\n   *         <li>If <i>m</i> is infinity, it is represented by the characters <code>\"Infinity\"\n   *             </code>; thus, positive infinity produces the result <code>\"Infinity\"</code> and\n   *             negative infinity produces the result <code>\"-Infinity\"</code>.\n   *         <li>If <i>m</i> is zero, it is represented by the characters <code>\"0.0\"</code>; thus,\n   *             negative zero produces the result <code>\"-0.0\"</code> and positive zero produces\n   *             the result <code>\"0.0\"</code>.\n   *         <li>If <i>m</i> is greater than or equal to 10<sup>-3</sup> but less than\n   *             10<sup>7</sup>, then it is represented as the integer part of <i>m</i>, in decimal\n   *             form with no leading zeroes, followed by '<code>.</code>' (<code>'&#92;u002E'\n   *             </code>), followed by one or more decimal digits representing the fractional part\n   *             of <i>m</i>.\n   *         <li>If <i>m</i> is less than 10<sup>-3</sup> or greater than or equal to\n   *             10<sup>7</sup>, then it is represented in so-called \"computerized scientific\n   *             notation.\" Let <i>n</i> be the unique integer such that 10<sup><i>n</i> </sup>&lt;=\n   *             <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the mathematically\n   *             exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so that 1 &lt;= <i>a</i> &lt;\n   *             10. The magnitude is then represented as the integer part of <i>a</i>, as a single\n   *             decimal digit, followed by '<code>.</code>' (<code>'&#92;u002E'</code>), followed\n   *             by decimal digits representing the fractional part of <i>a</i>, followed by the\n   *             letter '<code>E</code>' (<code>'&#92;u0045'</code>), followed by a representation\n   *             of <i>n</i> as a decimal integer, as produced by the method <code>{@link\n   *      java.lang.Integer#toString(int)}</code>.\n   *       </ul>\n   * </ul>\n   *\n   * How many digits must be printed for the fractional part of <i>m</i> or <i>a</i>? There must be\n   * at least one digit to represent the fractional part, and beyond that as many, but only as many,\n   * more digits as are needed to uniquely distinguish the argument value from adjacent values of\n   * type <code>float</code>. That is, suppose that <i>x</i> is the exact mathematical value\n   * represented by the decimal representation produced by this method for a finite nonzero argument\n   * <i>f</i>. Then <i>f</i> must be the <code>float</code> value nearest to <i>x</i>; or, if two\n   * <code>float</code> values are equally close to <i>x</i>, then <i>f</i> must be one of them and\n   * the least significant bit of the significand of <i>f</i> must be <code>0</code>.\n   *\n   * <p>\n   *\n   * @param f the float to be converted.\n   * @return a string representation of the argument.\n   */\n  public static String str(float f) {\n    return Strings.str(f);\n  }\n\n  /**\n   * Returns a string representation of the <code>double</code> argument. All characters mentioned\n   * below are ASCII characters.\n   *\n   * <ul>\n   *   <li>If the argument is NaN, the result is the string &quot;<code>NaN</code>&quot;.\n   *   <li>Otherwise, the result is a string that represents the sign and magnitude (absolute value)\n   *       of the argument. If the sign is negative, the first character of the result is '<code>-\n   *       </code>' (<code>'&#92;u002D'</code>); if the sign is positive, no sign character appears\n   *       in the result. As for the magnitude <i>m</i>:\n   *       <ul>\n   *         <li>If <i>m</i> is infinity, it is represented by the characters <code>\"Infinity\"\n   *             </code>; thus, positive infinity produces the result <code>\"Infinity\"</code> and\n   *             negative infinity produces the result <code>\"-Infinity\"</code>.\n   *         <li>If <i>m</i> is zero, it is represented by the characters <code>\"0.0\"</code>; thus,\n   *             negative zero produces the result <code>\"-0.0\"</code> and positive zero produces\n   *             the result <code>\"0.0\"</code>.\n   *         <li>If <i>m</i> is greater than or equal to 10<sup>-3</sup> but less than\n   *             10<sup>7</sup>, then it is represented as the integer part of <i>m</i>, in decimal\n   *             form with no leading zeroes, followed by '<code>.</code>' (<code>'&#92;u002E'\n   *             </code>), followed by one or more decimal digits representing the fractional part\n   *             of <i>m</i>.\n   *         <li>If <i>m</i> is less than 10<sup>-3</sup> or greater than or equal to\n   *             10<sup>7</sup>, then it is represented in so-called \"computerized scientific\n   *             notation.\" Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup> &lt;=\n   *             <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the mathematically\n   *             exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so that 1 &lt;= <i>a</i> &lt;\n   *             10. The magnitude is then represented as the integer part of <i>a</i>, as a single\n   *             decimal digit, followed by '<code>.</code>' (<code>'&#92;u002E'</code>), followed\n   *             by decimal digits representing the fractional part of <i>a</i>, followed by the\n   *             letter '<code>E</code>' (<code>'&#92;u0045'</code>), followed by a representation\n   *             of <i>n</i> as a decimal integer, as produced by the method {@link\n   *             Integer#toString(int)}.\n   *       </ul>\n   * </ul>\n   *\n   * How many digits must be printed for the fractional part of <i>m</i> or <i>a</i>? There must be\n   * at least one digit to represent the fractional part, and beyond that as many, but only as many,\n   * more digits as are needed to uniquely distinguish the argument value from adjacent values of\n   * type <code>double</code>. That is, suppose that <i>x</i> is the exact mathematical value\n   * represented by the decimal representation produced by this method for a finite nonzero argument\n   * <i>d</i>. Then <i>d</i> must be the <code>double</code> value nearest to <i>x</i>; or if two\n   * <code>double</code> values are equally close to <i>x</i>, then <i>d</i> must be one of them and\n   * the least significant bit of the significand of <i>d</i> must be <code>0</code>.\n   *\n   * <p>\n   *\n   * @param d the <code>double</code> to be converted.\n   * @return a string representation of the argument.\n   */\n  public static String str(double d) {\n    return Strings.str(d);\n  }\n\n  /**\n   * Exits the BTrace session -- note that the particular client's tracing session exits and not the\n   * observed/traced program! After exit call, the trace action method terminates immediately and no\n   * other probe action method (of that client) will be called after that.\n   *\n   * @param exitCode exit value sent to the client\n   */\n  public static void exit(int exitCode) {\n    Sys.exit(exitCode);\n  }\n\n  /**\n   * This is same as exit(int) except that the exit code is zero.\n   *\n   * @see #exit(int)\n   */\n  public static void exit() {\n    Sys.exit();\n  }\n\n  /** accessing jvmstat (perf) int counter */\n  public static long perfInt(String name) {\n    return Counters.perfInt(name);\n  }\n\n  /** accessing jvmstat (perf) long counter */\n  public static long perfLong(String name) {\n    return Counters.perfLong(name);\n  }\n\n  /** accessing jvmstat (perf) String counter */\n  public static String perfString(String name) {\n    return Counters.perfString(name);\n  }\n\n  /** Operating on maps */\n  // Create a new map\n  public static <K, V> Map<K, V> newHashMap() {\n    return Collections.newHashMap();\n  }\n\n  public static <K, V> Map<K, V> newWeakMap() {\n    return Collections.newWeakMap();\n  }\n\n  public static <V> Deque<V> newDeque() {\n    return Collections.newDeque();\n  }\n\n  // get a particular item from a Map\n  public static <K, V> V get(Map<K, V> map, K key) {\n    return Collections.get(map, key);\n  }\n\n  // check whether an item exists\n  public static <K, V> boolean containsKey(Map<K, V> map, K key) {\n    return Collections.containsKey(map, key);\n  }\n\n  public static <K, V> boolean containsValue(Map<K, V> map, V value) {\n    return Collections.containsValue(map, value);\n  }\n\n  // put a particular item into a Map\n  public static <K, V> V put(Map<K, V> map, K key, V value) {\n    return Collections.put(map, key, value);\n  }\n\n  // remove a particular item from a Map\n  public static <K, V> V remove(Map<K, V> map, K key) {\n    return Collections.remove(map, key);\n  }\n\n  // clear all items from a Map\n  public static <K, V> void clear(Map<K, V> map) {\n    Collections.clear(map);\n  }\n\n  // return the size of a Map\n  public static <K, V> int size(Map<K, V> map) {\n    return Collections.size(map);\n  }\n\n  public static <K, V> boolean isEmpty(Map<K, V> map) {\n    return Collections.isEmpty(map);\n  }\n\n  // operations on collections\n  public static <E> int size(Collection<E> coll) {\n    return Collections.size(coll);\n  }\n\n  public static <E> boolean isEmpty(Collection<E> coll) {\n    return Collections.isEmpty(coll);\n  }\n\n  public static <E> boolean contains(Collection<E> coll, Object obj) {\n    return Collections.contains(coll, obj);\n  }\n\n  public static boolean contains(Object[] array, Object value) {\n    return Collections.contains(array, value);\n  }\n\n  // operations on Deque\n  public static <V> void push(Deque<V> queue, V value) {\n    Collections.push(queue, value);\n  }\n\n  public static <V> V poll(Deque<V> queue) {\n    return Collections.poll(queue);\n  }\n\n  public static <V> V peek(Deque<V> queue) {\n    return Collections.peek(queue);\n  }\n\n  public static <V> void addLast(Deque<V> queue, V value) {\n    Collections.addLast(queue, value);\n  }\n\n  public static <V> V peekFirst(Deque<V> queue) {\n    return Collections.peekFirst(queue);\n  }\n\n  public static <V> V peekLast(Deque<V> queue) {\n    return Collections.peekLast(queue);\n  }\n\n  public static <V> V removeLast(Deque<V> queue) {\n    return Collections.removeLast(queue);\n  }\n\n  public static <V> V removeFirst(Deque<V> queue) {\n    return Collections.removeFirst(queue);\n  }\n\n  /**\n   * Returns the current instrumentation level.\n   *\n   * <p>Instrumentation level is used in evaluating {@linkplain OnMethod#enableAt()} expressions to\n   * enable/disable the probe handler.\n   *\n   * @return the instrumentation level (non negative integer)\n   * @since 1.3.4\n   */\n  public static int getInstrumentationLevel() {\n    return BTraceRuntime.getInstrumentationLevel();\n  }\n\n  /**\n   * Sets the current instrumentation level.\n   *\n   * <p>Instrumentation level is used in evaluating {@linkplain OnMethod#enableAt()} expressions to\n   * enable/disable the probe handler.\n   *\n   * @param level an arbitrary non negative integer number\n   * @since 1.3.4\n   */\n  public static void setInstrumentationLevel(int level) {\n    if (level >= 0) {\n      BTraceRuntime.setInstrumentationLevel(level);\n    }\n  }\n\n  /**\n   * Returns n'th command line argument. <code>null</code> if not available.\n   *\n   * @param n command line argument index\n   * @return n'th command line argument\n   */\n  public static String $(int n) {\n    return Sys.$(n);\n  }\n\n  /** Returns the process id of the currently BTrace'd process. */\n  public static int getpid() {\n    return Sys.getpid();\n  }\n\n  /** Returns the number of command line arguments. */\n  public static int $length() {\n    return Sys.$length();\n  }\n\n  // atomic stuff\n\n  /**\n   * Creates a new AtomicInteger with the given initial value.\n   *\n   * @param initialValue the initial value\n   */\n  public static AtomicInteger newAtomicInteger(int initialValue) {\n    return Atomic.newAtomicInteger(initialValue);\n  }\n\n  /**\n   * Gets the current value of the given AtomicInteger.\n   *\n   * @param ai AtomicInteger whose value is returned.\n   * @return the current value\n   */\n  public static int get(AtomicInteger ai) {\n    return Atomic.get(ai);\n  }\n\n  /**\n   * Sets to the given value to the given AtomicInteger.\n   *\n   * @param ai AtomicInteger whose value is set.\n   * @param newValue the new value\n   */\n  public static void set(AtomicInteger ai, int newValue) {\n    Atomic.set(ai, newValue);\n  }\n\n  /**\n   * Eventually sets to the given value to the given AtomicInteger.\n   *\n   * @param ai AtomicInteger whose value is lazily set.\n   * @param newValue the new value\n   */\n  public static void lazySet(AtomicInteger ai, int newValue) {\n    Atomic.lazySet(ai, newValue);\n  }\n\n  /**\n   * Atomically sets the value of given AtomitInteger to the given updated value if the current\n   * value {@code ==} the expected value.\n   *\n   * @param ai AtomicInteger whose value is compared and set.\n   * @param expect the expected value\n   * @param update the new value\n   * @return true if successful. False return indicates that the actual value was not equal to the\n   *     expected value.\n   */\n  public static boolean compareAndSet(AtomicInteger ai, int expect, int update) {\n    return Atomic.compareAndSet(ai, expect, update);\n  }\n\n  /**\n   * Atomically sets the value to the given updated value if the current value {@code ==} the\n   * expected value.\n   *\n   * <p>May <a href=\"package-summary.html#Spurious\">fail spuriously</a> and does not provide\n   * ordering guarantees, so is only rarely an appropriate alternative to {@code compareAndSet}.\n   *\n   * @param ai AtomicInteger whose value is weakly compared and set.\n   * @param expect the expected value\n   * @param update the new value\n   * @return true if successful.\n   */\n  public static boolean weakCompareAndSet(AtomicInteger ai, int expect, int update) {\n    return Atomic.weakCompareAndSet(ai, expect, update);\n  }\n\n  /**\n   * Atomically increments by one the current value of given AtomicInteger.\n   *\n   * @param ai AtomicInteger that is incremented.\n   * @return the previous value\n   */\n  public static int getAndIncrement(AtomicInteger ai) {\n    return Atomic.getAndIncrement(ai);\n  }\n\n  /**\n   * Atomically decrements by one the current value of given AtomicInteger.\n   *\n   * @param ai AtomicInteger that is decremented.\n   * @return the previous value\n   */\n  public static int getAndDecrement(AtomicInteger ai) {\n    return Atomic.getAndDecrement(ai);\n  }\n\n  /**\n   * Atomically increments by one the current value of given AtomicInteger.\n   *\n   * @param ai AtomicInteger that is incremented.\n   * @return the updated value\n   */\n  public static int incrementAndGet(AtomicInteger ai) {\n    return Atomic.incrementAndGet(ai);\n  }\n\n  /**\n   * Atomically decrements by one the current value of given AtomicInteger.\n   *\n   * @param ai AtomicInteger whose value is decremented.\n   * @return the updated value\n   */\n  public static int decrementAndGet(AtomicInteger ai) {\n    return Atomic.decrementAndGet(ai);\n  }\n\n  /**\n   * Atomically adds the given value to the current value.\n   *\n   * @param ai AtomicInteger whose value is added to.\n   * @param delta the value to add\n   * @return the previous value\n   */\n  public static int getAndAdd(AtomicInteger ai, int delta) {\n    return Atomic.getAndAdd(ai, delta);\n  }\n\n  /**\n   * Atomically adds the given value to the current value.\n   *\n   * @param ai AtomicInteger whose value is added to.\n   * @param delta the value to add\n   * @return the updated value\n   */\n  public static int addAndGet(AtomicInteger ai, int delta) {\n    return Atomic.addAndGet(ai, delta);\n  }\n\n  /**\n   * Atomically sets to the given value and returns the old value.\n   *\n   * @param ai AtomicInteger whose value is set.\n   * @param newValue the new value\n   * @return the previous value\n   */\n  public static int getAndSet(AtomicInteger ai, int newValue) {\n    return Atomic.getAndSet(ai, newValue);\n  }\n\n  /**\n   * Creates a new AtomicLong with the given initial value.\n   *\n   * @param initialValue the initial value\n   */\n  public static AtomicLong newAtomicLong(long initialValue) {\n    return Atomic.newAtomicLong(initialValue);\n  }\n\n  /**\n   * Gets the current value the given AtomicLong.\n   *\n   * @param al AtomicLong whose value is returned.\n   * @return the current value\n   */\n  public static long get(AtomicLong al) {\n    return Atomic.get(al);\n  }\n\n  /**\n   * Sets to the given value.\n   *\n   * @param al AtomicLong whose value is set.\n   * @param newValue the new value\n   */\n  public static void set(AtomicLong al, long newValue) {\n    Atomic.set(al, newValue);\n  }\n\n  /**\n   * Eventually sets to the given value to the given AtomicLong.\n   *\n   * @param al AtomicLong whose value is set.\n   * @param newValue the new value\n   */\n  public static void lazySet(AtomicLong al, long newValue) {\n    Atomic.lazySet(al, newValue);\n  }\n\n  /**\n   * Atomically sets the value to the given updated value if the current value {@code ==} the\n   * expected value.\n   *\n   * @param al AtomicLong whose value is compared and set.\n   * @param expect the expected value\n   * @param update the new value\n   * @return true if successful. False return indicates that the actual value was not equal to the\n   *     expected value.\n   */\n  public static boolean compareAndSet(AtomicLong al, long expect, long update) {\n    return Atomic.compareAndSet(al, expect, update);\n  }\n\n  /**\n   * Atomically sets the value to the given updated value if the current value {@code ==} the\n   * expected value.\n   *\n   * <p>May fail spuriously and does not provide ordering guarantees, so is only rarely an\n   * appropriate alternative to {@code compareAndSet}.\n   *\n   * @param al AtomicLong whose value is compared and set.\n   * @param expect the expected value\n   * @param update the new value\n   * @return true if successful.\n   */\n  public static boolean weakCompareAndSet(AtomicLong al, long expect, long update) {\n    return Atomic.weakCompareAndSet(al, expect, update);\n  }\n\n  /**\n   * Atomically increments by one the current value.\n   *\n   * @param al AtomicLong whose value is incremented.\n   * @return the previous value\n   */\n  public static long getAndIncrement(AtomicLong al) {\n    return Atomic.getAndIncrement(al);\n  }\n\n  /**\n   * Atomically decrements by one the current value.\n   *\n   * @param al AtomicLong whose value is decremented.\n   * @return the previous value\n   */\n  public static long getAndDecrement(AtomicLong al) {\n    return Atomic.getAndDecrement(al);\n  }\n\n  /**\n   * Atomically increments by one the current value.\n   *\n   * @param al AtomicLong whose value is incremented.\n   * @return the updated value\n   */\n  public static long incrementAndGet(AtomicLong al) {\n    return Atomic.incrementAndGet(al);\n  }\n\n  /**\n   * Atomically decrements by one the current value.\n   *\n   * @param al AtomicLong whose value is decremented.\n   * @return the updated value\n   */\n  public static long decrementAndGet(AtomicLong al) {\n    return Atomic.decrementAndGet(al);\n  }\n\n  /**\n   * Atomically adds the given value to the current value.\n   *\n   * @param al AtomicLong whose value is added to.\n   * @param delta the value to add\n   * @return the previous value\n   */\n  public static long getAndAdd(AtomicLong al, long delta) {\n    return Atomic.getAndAdd(al, delta);\n  }\n\n  /**\n   * Atomically adds the given value to the current value.\n   *\n   * @param al AtomicLong whose value is added to\n   * @param delta the value to add\n   * @return the updated value\n   */\n  public static long addAndGet(AtomicLong al, long delta) {\n    return Atomic.addAndGet(al, delta);\n  }\n\n  /**\n   * Atomically sets to the given value and returns the old value.\n   *\n   * @param al AtomicLong that is set.\n   * @param newValue the new value\n   * @return the previous value\n   */\n  public static long getAndSet(AtomicLong al, long newValue) {\n    return Atomic.getAndSet(al, newValue);\n  }\n\n  /**\n   * BTrace to DTrace communication chennal. Raise DTrace USDT probe from BTrace.\n   *\n   * @see #dtraceProbe(String, String, int, int)\n   */\n  public static int dtraceProbe(String str1, String str2) {\n    return D.probe(str1, str2);\n  }\n\n  /**\n   * BTrace to DTrace communication chennal. Raise DTrace USDT probe from BTrace.\n   *\n   * @see #dtraceProbe(String, String, int, int)\n   */\n  public static int dtraceProbe(String str1, String str2, int i1) {\n    return D.probe(str1, str2, i1);\n  }\n\n  /**\n   * BTrace to DTrace communication channel. Raise DTrace USDT probe from BTrace.\n   *\n   * @param str1 first String param to DTrace probe\n   * @param str2 second String param to DTrace probe\n   * @param i1 first int param to DTrace probe\n   * @param i2 second int param to DTrace probe\n   */\n  public static int dtraceProbe(String str1, String str2, int i1, int i2) {\n    return D.probe(str1, str2, i1, i2);\n  }\n\n  /**\n   * Gets the system property indicated by the specified key.\n   *\n   * @param key the name of the system property.\n   * @return the string value of the system property, or <code>null</code> if there is no property\n   *     with that key.\n   * @throws NullPointerException if <code>key</code> is <code>null</code>.\n   * @throws IllegalArgumentException if <code>key</code> is empty.\n   */\n  public static String property(String key) {\n    return Sys.Env.property(key);\n  }\n\n  /**\n   * Returns all Sys properties.\n   *\n   * @return the system properties\n   */\n  public static Properties properties() {\n    return Sys.Env.properties();\n  }\n\n  /** Prints all Sys properties. */\n  public static void printProperties() {\n    Sys.Env.printProperties();\n  }\n\n  /**\n   * Gets the value of the specified environment variable. An environment variable is a\n   * system-dependent external named value.\n   *\n   * @param name the name of the environment variable\n   * @return the string value of the variable, or <code>null</code> if the variable is not defined\n   *     in the system environment\n   * @throws NullPointerException if <code>name</code> is <code>null</code>\n   */\n  public static String getenv(String name) {\n    return Sys.Env.getenv(name);\n  }\n\n  /**\n   * Returns an unmodifiable string map view of the current system environment. The environment is a\n   * system-dependent mapping from names to values which is passed from parent to child processes.\n   *\n   * @return the environment as a map of variable names to values\n   */\n  public static Map<String, String> getenv() {\n    return Sys.Env.getenv();\n  }\n\n  /** Prints all system environment values. */\n  public static void printEnv() {\n    Sys.Env.printEnv();\n  }\n\n  /**\n   * Returns the number of processors available to the Java virtual machine.\n   *\n   * <p>This value may change during a particular invocation of the virtual machine. Applications\n   * that are sensitive to the number of available processors should therefore occasionally poll\n   * this property and adjust their resource usage appropriately.\n   *\n   * @return the maximum number of processors available to the virtual machine; never smaller than\n   *     one\n   */\n  public static long availableProcessors() {\n    return Sys.Env.availableProcessors();\n  }\n\n  // memory usage\n\n  /**\n   * Returns the amount of free memory in the Java Virtual Machine. Calling the <code>gc</code>\n   * method may result in increasing the value returned by <code>freeMemory.</code>\n   *\n   * @return an approximation to the total amount of memory currently available for future allocated\n   *     objects, measured in bytes.\n   */\n  public static long freeMemory() {\n    return Sys.Memory.freeMemory();\n  }\n\n  /**\n   * Returns the total amount of memory in the Java virtual machine. The value returned by this\n   * method may vary over time, depending on the host environment.\n   *\n   * <p>Note that the amount of memory required to hold an object of any given type may be\n   * implementation-dependent.\n   *\n   * @return the total amount of memory currently available for current and future objects, measured\n   *     in bytes.\n   */\n  public static long totalMemory() {\n    return Sys.Memory.totalMemory();\n  }\n\n  /**\n   * Returns the maximum amount of memory that the Java virtual machine will attempt to use. If\n   * there is no inherent limit then the value {@link java.lang.Long#MAX_VALUE} will be returned.\n   *\n   * @return the maximum amount of memory that the virtual machine will attempt to use, measured in\n   *     bytes\n   */\n  public static long maxMemory() {\n    return Sys.Memory.maxMemory();\n  }\n\n  /** Returns heap memory usage */\n  public static MemoryUsage heapUsage() {\n    return Sys.Memory.heapUsage();\n  }\n\n  /** Returns non-heap memory usage */\n  public static MemoryUsage nonHeapUsage() {\n    return Sys.Memory.nonHeapUsage();\n  }\n\n  /**\n   * Returns the amount of memory in bytes that the Java virtual machine initially requests from the\n   * operating system for memory management.\n   */\n  public static long init(MemoryUsage mu) {\n    return Sys.Memory.init(mu);\n  }\n\n  /**\n   * Returns the amount of memory in bytes that is committed for the Java virtual machine to use.\n   * This amount of memory is guaranteed for the Java virtual machine to use.\n   */\n  public static long committed(MemoryUsage mu) {\n    return Sys.Memory.committed(mu);\n  }\n\n  /**\n   * Returns the maximum amount of memory in bytes that can be used for memory management. This\n   * method returns -1 if the maximum memory size is undefined.\n   */\n  public static long max(MemoryUsage mu) {\n    return Sys.Memory.max(mu);\n  }\n\n  /** Returns the amount of used memory in bytes. */\n  public static long used(MemoryUsage mu) {\n    return Sys.Memory.used(mu);\n  }\n\n  /** Returns the approximate number of objects for which finalization is pending. */\n  public static long finalizationCount() {\n    return Sys.Memory.finalizationCount();\n  }\n\n  /**\n   * Returns the input arguments passed to the Java virtual machine which does not include the\n   * arguments to the <tt>main</tt> method. This method returns an empty list if there is no input\n   * argument to the Java virtual machine.\n   *\n   * <p>Some Java virtual machine implementations may take input arguments from multiple different\n   * sources: for examples, arguments passed from the application that launches the Java virtual\n   * machine such as the 'java' command, environment variables, configuration files, etc.\n   *\n   * <p>Typically, not all command-line options to the 'java' command are passed to the Java virtual\n   * machine. Thus, the returned input arguments may not include all command-line options.\n   *\n   * @return a list of <tt>String</tt> objects; each element is an argument passed to the Java\n   *     virtual machine.\n   */\n  public static List<String> vmArguments() {\n    return Sys.VM.vmArguments();\n  }\n\n  /**\n   * Prints VM input arguments list.\n   *\n   * @see #vmArguments\n   */\n  public static void printVmArguments() {\n    Sys.VM.printVmArguments();\n  }\n\n  /**\n   * Returns the Java virtual machine implementation version. This method is equivalent to\n   * <b>Sys.getProperty(\"java.vm.version\")</b>.\n   *\n   * @return the Java virtual machine implementation version.\n   */\n  public static String vmVersion() {\n    return Sys.VM.vmVersion();\n  }\n\n  /**\n   * Tests if the Java virtual machine supports the boot class path mechanism used by the bootstrap\n   * class loader to search for class files.\n   *\n   * @return <tt>true</tt> if the Java virtual machine supports the class path mechanism;\n   *     <tt>false</tt> otherwise.\n   */\n  public static boolean isBootClassPathSupported() {\n    return Sys.VM.isBootClassPathSupported();\n  }\n\n  /**\n   * Returns the boot class path that is used by the bootstrap class loader to search for class\n   * files.\n   *\n   * <p>Multiple paths in the boot class path are separated by the path separator character of the\n   * platform on which the Java virtual machine is running.\n   *\n   * <p>A Java virtual machine implementation may not support the boot class path mechanism for the\n   * bootstrap class loader to search for class files. The {@link #isBootClassPathSupported} method\n   * can be used to determine if the Java virtual machine supports this method.\n   *\n   * @return the boot class path.\n   * @throws java.lang.UnsupportedOperationException if the Java virtual machine does not support\n   *     this operation.\n   */\n  public static String bootClassPath() {\n    return Sys.VM.bootClassPath();\n  }\n\n  /**\n   * Returns the Java class path that is used by the system class loader to search for class files.\n   * This method is equivalent to <b>Sys.getProperty(\"java.class.path\")</b>.\n   *\n   * @return the Java class path.\n   */\n  public static String classPath() {\n    return Sys.VM.classPath();\n  }\n\n  /**\n   * Returns the Java library path. This method is equivalent to\n   * <b>Sys.getProperty(\"java.library.path\")</b>.\n   *\n   * <p>Multiple paths in the Java library path are separated by the path separator character of the\n   * platform of the Java virtual machine being monitored.\n   *\n   * @return the Java library path.\n   */\n  public static String libraryPath() {\n    return Sys.VM.libraryPath();\n  }\n\n  /**\n   * Returns the current number of live threads including both daemon and non-daemon threads.\n   *\n   * @return the current number of live threads.\n   */\n  public static long threadCount() {\n    return Sys.VM.threadCount();\n  }\n\n  /**\n   * Returns the peak live thread count since the Java virtual machine started or peak was reset.\n   *\n   * @return the peak live thread count.\n   */\n  public static long peakThreadCount() {\n    return Sys.VM.peakThreadCount();\n  }\n\n  /**\n   * Returns the total number of threads created and also started since the Java virtual machine\n   * started.\n   *\n   * @return the total number of threads started.\n   */\n  public static long totalStartedThreadCount() {\n    return Sys.VM.totalStartedThreadCount();\n  }\n\n  /**\n   * Returns the current number of live daemon threads.\n   *\n   * @return the current number of live daemon threads.\n   */\n  public static long daemonThreadCount() {\n    return Sys.VM.daemonThreadCount();\n  }\n\n  /**\n   * Returns the total CPU time for the current thread in nanoseconds. The returned value is of\n   * nanoseconds precision but not necessarily nanoseconds accuracy. If the implementation\n   * distinguishes between user mode time and system mode time, the returned CPU time is the amount\n   * of time that the current thread has executed in user mode or system mode.\n   */\n  public static long currentThreadCpuTime() {\n    return Sys.VM.currentThreadCpuTime();\n  }\n\n  /**\n   * Returns the CPU time that the current thread has executed in user mode in nanoseconds. The\n   * returned value is of nanoseconds precision but not necessarily nanoseconds accuracy.\n   */\n  public static long currentThreadUserTime() {\n    return Sys.VM.currentThreadUserTime();\n  }\n\n  /**\n   * Returns the total amount of time spent in GarbageCollection up to this point since the\n   * application was started.\n   *\n   * @return Returns the amount of overall time spent in GC\n   */\n  public static long getTotalGcTime() {\n    return Sys.Memory.getTotalGcTime();\n  }\n\n  /**\n   * Returns an implementation-specific approximation of the amount of storage consumed by the\n   * specified object. The result may include some or all of the object's overhead, and thus is\n   * useful for comparison within an implementation but not between implementations.\n   *\n   * <p>The estimate may change during a single invocation of the JVM.\n   *\n   * @param objectToSize the object to size\n   * @return an implementation-specific approximation of the amount of storage consumed by the\n   *     specified object\n   * @throws java.lang.NullPointerException if the supplied Object is <code>null</code>.\n   */\n  public static long sizeof(Object objectToSize) {\n    return BTraceRuntime.sizeof(objectToSize);\n  }\n\n  /**\n   * Dump the snapshot of the Java heap to a file in hprof binary format. Only the live objects are\n   * dumped. Under the current dir of traced app, ./btrace&lt;pid&gt;/btrace-class/ directory is\n   * created. Under that directory, a file of given fileName is created.\n   *\n   * @param fileName name of the file to which heap is dumped\n   */\n  public static void dumpHeap(String fileName) {\n    Sys.Memory.dumpHeap(fileName);\n  }\n\n  /**\n   * Dump the snapshot of the Java heap to a file in hprof binary format. Under the current dir of\n   * traced app, ./btrace&lt;pid&gt;/btrace-class/ directory is created. Under that directory, a\n   * file of given fileName is created.\n   *\n   * @param fileName name of the file to which heap is dumped\n   * @param live flag that tells whether only live objects are to be dumped or all objects are to be\n   *     dumped.\n   */\n  public static void dumpHeap(String fileName, boolean live) {\n    Sys.Memory.dumpHeap(fileName, live);\n  }\n\n  /**\n   * Runs the garbage collector.\n   *\n   * <p>Calling the <code>gc</code> method suggests that the Java Virtual Machine expend effort\n   * toward recycling unused objects in order to make the memory they currently occupy available for\n   * quick reuse. When control returns from the method call, the Java Virtual Machine has made a\n   * best effort to reclaim space from all discarded objects. This method calls Sys.gc() to perform\n   * GC.\n   */\n  public static void gc() {\n    Sys.Memory.gc();\n  }\n\n  /**\n   * Runs the finalization methods of any objects pending finalization.\n   *\n   * <p>Calling this method suggests that the Java Virtual Machine expend effort toward running the\n   * <code>finalize</code> methods of objects that have been found to be discarded but whose <code>\n   * finalize</code> methods have not yet been run. When control returns from the method call, the\n   * Java Virtual Machine has made a best effort to complete all outstanding finalizations. This\n   * method calls Sys.runFinalization() to run finalization.\n   */\n  public static void runFinalization() {\n    Sys.Memory.runFinalization();\n  }\n\n  /**\n   * Serialize a given object into the given file. Under the current dir of traced app,\n   * ./btrace&lt;pid&gt;/btrace-class/ directory is created. Under that directory, a file of given\n   * fileName is created.\n   *\n   * @param obj object that has to be serialized.\n   * @param fileName name of the file to which the object is serialized.\n   */\n  public static void serialize(Serializable obj, String fileName) {\n    Export.serialize(obj, fileName);\n  }\n\n  /**\n   * Creates an XML document to persist the tree of the all transitively reachable objects from\n   * given \"root\" object.\n   */\n  public static String toXML(Object obj) {\n    return Export.toXML(obj);\n  }\n\n  /**\n   * Writes an XML document to persist the tree of the all the transitively reachable objects from\n   * the given \"root\" object. Under the current dir of traced app, ./btrace&lt;pid&gt;/btrace-class/\n   * directory is created. Under that directory, a file of the given fileName is created.\n   */\n  public static void writeXML(Object obj, String fileName) {\n    Export.writeXML(obj, fileName);\n  }\n\n  /**\n   * Writes a .dot document to persist the tree of the all the transitively reachable objects from\n   * the given \"root\" object. .dot documents can be viewed by Graphviz application\n   * (www.graphviz.org) Under the current dir of traced app, ./btrace&lt;pid&gt;/btrace-class/\n   * directory is created. Under that directory, a file of the given fileName is created.\n   *\n   * @since 1.1\n   */\n  public static void writeDOT(Object obj, String fileName) {\n    Export.writeDOT(obj, fileName);\n  }\n\n  // speculative buffer management\n\n  /**\n   * Returns an identifier for a new speculative buffer.\n   *\n   * @return new speculative buffer id\n   */\n  public static int speculation() {\n    return Speculation.speculation();\n  }\n\n  /**\n   * Sets current speculative buffer id.\n   *\n   * @param id the speculative buffer id\n   */\n  public static void speculate(int id) {\n    Speculation.speculate(id);\n  }\n\n  /**\n   * Commits the speculative buffer associated with id.\n   *\n   * @param id the speculative buffer id\n   */\n  public static void commit(int id) {\n    Speculation.commit(id);\n  }\n\n  /**\n   * Discards the speculative buffer associated with id.\n   *\n   * @param id the speculative buffer id\n   */\n  public static void discard(int id) {\n    Speculation.discard(id);\n  }\n\n  // Internals only below this point\n  private static void checkStatic(Field field) {\n    if (!Modifier.isStatic(field.getModifiers())) {\n      throw new IllegalArgumentException(field.getName() + \" is not a static field\");\n    }\n  }\n\n  private static Field getField(Class<?> clazz, String name, boolean throwError) {\n    return AccessController.doPrivileged(\n        (PrivilegedAction<Field>)\n            () -> {\n              Field field = null;\n              Class<?> cClass = clazz;\n              try {\n                while (Objects.isNull(field) && Objects.nonNull(cClass)) {\n                  try {\n                    field = cClass.getDeclaredField(name);\n                  } catch (NoSuchFieldException exp) {\n                    // Ignore the exception and continue looking for the parent class\n                    cClass = cClass.getSuperclass();\n                  }\n                }\n\n                if (Objects.isNull(cClass)) {\n                  throw new NoSuchFieldException(name);\n                }\n\n                field.setAccessible(true);\n\n                return field;\n              } catch (Exception exp) {\n                if (throwError) {\n                  throw translate(exp);\n                } else {\n                  return null;\n                }\n              }\n            });\n  }\n\n  private static Field[] getAllFields(Class<?> clazz) {\n    return AccessController.doPrivileged(\n        (PrivilegedAction<Field[]>)\n            () -> {\n              try {\n                Field[] fields = clazz.getDeclaredFields();\n                for (Field f : fields) {\n                  f.setAccessible(true);\n                }\n                return fields;\n              } catch (Exception exp) {\n                throw translate(exp);\n              }\n            });\n  }\n\n  private static void addFieldValues(\n      StringBuilder buf, Object obj, Class<?> clazz, boolean classNamePrefix) {\n    Field[] fields = getAllFields(clazz);\n    for (Field f : fields) {\n      int modifiers = f.getModifiers();\n      if (!Modifier.isStatic(modifiers)) {\n        if (classNamePrefix) {\n          buf.append(f.getDeclaringClass().getName());\n          buf.append('.');\n        }\n        buf.append(f.getName());\n        buf.append('=');\n        try {\n          buf.append(Strings.str(f.get(obj)));\n        } catch (Exception exp) {\n          throw translate(exp);\n        }\n        buf.append(\", \");\n      }\n    }\n    Class<?> sc = clazz.getSuperclass();\n    if (sc != null) {\n      addFieldValues(buf, obj, sc, classNamePrefix);\n    }\n  }\n\n  private static void addStaticFieldValues(\n      StringBuilder buf, Class<?> clazz, boolean classNamePrefix) {\n    Field[] fields = getAllFields(clazz);\n    for (Field f : fields) {\n      int modifiers = f.getModifiers();\n      if (Modifier.isStatic(modifiers)) {\n        if (classNamePrefix) {\n          buf.append(f.getDeclaringClass().getName());\n          buf.append('.');\n        }\n        buf.append(f.getName());\n        buf.append('=');\n        try {\n          buf.append(Strings.str(f.get(null)));\n        } catch (Exception exp) {\n          throw translate(exp);\n        }\n        buf.append(\", \");\n      }\n    }\n    Class<?> sc = clazz.getSuperclass();\n    if (sc != null) {\n      addStaticFieldValues(buf, sc, classNamePrefix);\n    }\n  }\n\n  private static RuntimeException translate(Exception exp) {\n    if (exp instanceof RuntimeException) {\n      return (RuntimeException) exp;\n    } else {\n      return new RuntimeException(exp);\n    }\n  }\n\n  /** ******** Namespaced methods ***************** */\n\n  /*\n   * Wraps the threads related BTrace utility methods\n   * @since 1.2\n   */\n  public static class Threads {\n    // Thread and stack access\n\n    /**\n     * Tests whether this thread has been interrupted. The <i>interrupted status</i> of the thread\n     * is unaffected by this method.\n     *\n     * <p>A thread interruption ignored because a thread was not alive at the time of the interrupt\n     * will be reflected by this method returning false.\n     *\n     * @return <code>true</code> if this thread has been interrupted; <code>false</code> otherwise.\n     */\n    public static boolean isInteruppted() {\n      return Thread.currentThread().isInterrupted();\n    }\n\n    /** Prints the java stack trace of the current thread. */\n    public static void jstack() {\n      jstack(1, -1);\n    }\n\n    /**\n     * Prints the java stack trace of the current thread. But, atmost given number of frames.\n     *\n     * @param numFrames number of frames to be printed. When this is negative all frames are\n     *     printed.\n     */\n    public static void jstack(int numFrames) {\n      // passing '5' to skip our own frames to generate stack trace\n      jstack(1, numFrames);\n    }\n\n    private static void jstack(int strip, int numFrames) {\n      if (numFrames == 0) return;\n      StackTraceElement[] st = Thread.currentThread().getStackTrace();\n      BTraceRuntime.stackTrace(st, strip + 2, numFrames);\n    }\n\n    /** Prints Java stack traces of all the Java threads. */\n    public static void jstackAll() {\n      jstackAll(1, -1);\n    }\n\n    /**\n     * Prints Java stack traces of all the Java threads. But, at most given number of frames.\n     *\n     * @param numFrames number of frames to be printed. When this is negative all frames are\n     *     printed.\n     */\n    public static void jstackAll(int numFrames) {\n      jstackAll(1, numFrames);\n    }\n\n    private static void jstackAll(int strip, int numFrames) {\n      BTraceRuntime.stackTraceAll(numFrames);\n    }\n\n    /**\n     * Returns the stack trace of current thread as a String.\n     *\n     * @return the stack trace as a String.\n     */\n    public static String jstackStr() {\n      return jstackStr(1, -1);\n    }\n\n    /**\n     * Returns the stack trace of the current thread as a String but includes atmost the given\n     * number of frames.\n     *\n     * @param numFrames number of frames to be included. When this is negative all frames are\n     *     included.\n     * @return the stack trace as a String.\n     */\n    public static String jstackStr(int numFrames) {\n      if (numFrames == 0) {\n        return \"\";\n      }\n      return jstackStr(1, numFrames);\n    }\n\n    private static String jstackStr(int strip, int numFrames) {\n      if (numFrames == 0) {\n        return \"\";\n      }\n      StackTraceElement[] st = Thread.currentThread().getStackTrace();\n      return BTraceRuntime.stackTraceStr(st, strip + 2, numFrames);\n    }\n\n    /**\n     * Returns the stack traces of all Java threads as a String.\n     *\n     * @return the stack traces as a String.\n     */\n    public static String jstackAllStr() {\n      return jstackAllStr(-1);\n    }\n\n    /**\n     * Returns atmost given number of frames in stack traces of all threads as a String.\n     *\n     * @param numFrames number of frames to be included. When this is negative all frames are\n     *     included.\n     * @return the stack traces as a String.\n     */\n    public static String jstackAllStr(int numFrames) {\n      if (numFrames == 0) {\n        return \"\";\n      }\n      return BTraceRuntime.stackTraceAllStr(numFrames);\n    }\n\n    /**\n     * Prints the stack trace of the given exception object.\n     *\n     * @param exception throwable for which stack trace is printed.\n     */\n    public static void jstack(Throwable exception) {\n      jstack(exception, -1);\n    }\n\n    /**\n     * Prints the stack trace of the given exception object. But, prints atmost given number of\n     * frames.\n     *\n     * @param exception throwable for which stack trace is printed.\n     * @param numFrames maximum number of frames to be printed.\n     */\n    public static void jstack(Throwable exception, int numFrames) {\n      if (numFrames == 0) {\n        return;\n      }\n      StackTraceElement[] st = exception.getStackTrace();\n      println(exception.toString());\n      BTraceRuntime.stackTrace(\"\\t\", st, 0, numFrames);\n      Throwable cause = exception.getCause();\n      while (cause != null) {\n        print(\"Caused by: \");\n        println(cause.toString());\n        st = cause.getStackTrace();\n        BTraceRuntime.stackTrace(\"\\t\", st, 0, numFrames);\n        cause = cause.getCause();\n      }\n    }\n\n    /**\n     * Returns the stack trace of given exception object as a String.\n     *\n     * @param exception the throwable for which stack trace is returned.\n     */\n    public static String jstackStr(Throwable exception) {\n      return jstackStr(exception, -1);\n    }\n\n    /**\n     * Returns stack trace of given exception object as a String.\n     *\n     * @param exception throwable for which stack trace is returned.\n     * @param numFrames maximum number of frames to be returned.\n     */\n    public static String jstackStr(Throwable exception, int numFrames) {\n      if (numFrames == 0) {\n        return \"\";\n      }\n      StackTraceElement[] st = exception.getStackTrace();\n      StringBuilder buf = new StringBuilder();\n      buf.append(Strings.str(exception));\n      buf.append(BTraceRuntime.stackTraceStr(\"\\t\", st, 0, numFrames));\n      Throwable cause = exception.getCause();\n      while (cause != null) {\n        buf.append(\"Caused by:\");\n        st = cause.getStackTrace();\n        buf.append(BTraceRuntime.stackTraceStr(\"\\t\", st, 0, numFrames));\n        cause = cause.getCause();\n      }\n      return buf.toString();\n    }\n\n    /**\n     * Returns a reference to the currently executing thread object.\n     *\n     * @return the currently executing thread.\n     */\n    public static Thread currentThread() {\n      return Thread.currentThread();\n    }\n\n    /**\n     * Returns the identifier of the given Thread. The thread ID is a positive <tt>long</tt> number\n     * generated when the given thread was created. The thread ID is unique and remains unchanged\n     * during its lifetime. When a thread is terminated, the thread ID may be reused.\n     */\n    public static long threadId(Thread thread) {\n      return thread.getId();\n    }\n\n    /**\n     * Returns the state of the given thread. This method is designed for use in monitoring of the\n     * system state, not for synchronization control.\n     */\n    public static Thread.State threadState(Thread thread) {\n      return thread.getState();\n    }\n\n    /**\n     * Returns <tt>true</tt> if and only if the current thread holds the monitor lock on the\n     * specified object.\n     *\n     * <p>This method is designed to allow a program to assert that the current thread already holds\n     * a specified lock:\n     *\n     * <pre>\n     *     assert Thread.holdsLock(obj);\n     * </pre>\n     *\n     * @param obj the object on which to test lock ownership\n     * @return <tt>true</tt> if the current thread holds the monitor lock on the specified object.\n     * @throws NullPointerException if obj is <tt>null</tt>\n     */\n    public static boolean holdsLock(Object obj) {\n      return Thread.holdsLock(obj);\n    }\n\n    /** Prints the Java level deadlocks detected (if any). */\n    public static void deadlocks() {\n      deadlocks(true);\n    }\n\n    /**\n     * Prints deadlocks detected (if any). Optionally prints stack trace of the deadlocked threads.\n     *\n     * @param stackTrace boolean flag to specify whether to print stack traces of deadlocked threads\n     *     or not.\n     */\n    public static void deadlocks(boolean stackTrace) {\n      BTraceRuntime.deadlocks(stackTrace);\n    }\n\n    /**\n     * Returns the name of the given thread.\n     *\n     * @param thread thread whose name is returned\n     */\n    public static String name(Thread thread) {\n      return thread.getName();\n    }\n  }\n\n  /*\n   * Wraps the strings related BTrace utility methods\n   * @since 1.2\n   */\n  public static class Strings {\n    public static boolean startsWith(String s, String start) {\n      return s.startsWith(start);\n    }\n\n    public static boolean endsWith(String s, String end) {\n      return s.endsWith(end);\n    }\n\n    /**\n     * This is synonym to \"concat\".\n     *\n     * @see #concat(String, String)\n     */\n    public static String strcat(String str1, String str2) {\n      return concat(str1, str2);\n    }\n\n    /** Concatenates the specified strings together. */\n    public static String concat(String str1, String str2) {\n      return str1.concat(str2);\n    }\n\n    /**\n     * Compares two strings lexicographically. The comparison is based on the Unicode value of each\n     * character in the strings. The character sequence represented by the first <code>String</code>\n     * object is compared lexicographically to the character sequence represented by the second\n     * string. The result is a negative integer if the first <code>String</code> object\n     * lexicographically precedes the second string. The result is a positive integer if the first\n     * <code>String</code> object lexicographically follows the second string. The result is zero if\n     * the strings are equal; <code>compareTo</code> returns <code>0</code> exactly when the {@link\n     * String#equals(Object)} method would return <code>true</code>.\n     */\n    public static int compareTo(String str1, String str2) {\n      return str1.compareTo(str2);\n    }\n\n    /**\n     * This is synonym to \"compareTo\" method.\n     *\n     * @see #compareTo\n     */\n    public static int strcmp(String str1, String str2) {\n      return str1.compareTo(str2);\n    }\n\n    /**\n     * Compares two strings lexicographically, ignoring case differences. This method returns an\n     * integer whose sign is that of calling <code>compareTo</code> with normalized versions of the\n     * strings where case differences have been eliminated by calling <code>\n     * Character.toLowerCase(Character.toUpperCase(character))</code> on each character.\n     */\n    public static int compareToIgnoreCase(String str1, String str2) {\n      return str1.compareToIgnoreCase(str2);\n    }\n\n    /**\n     * This is synonym to \"compareToIgnoreCase\".\n     *\n     * @see #compareToIgnoreCase\n     */\n    public static int stricmp(String str1, String str2) {\n      return str1.compareToIgnoreCase(str2);\n    }\n\n    /** Find String within String */\n    public static int strstr(String str1, String str2) {\n      return str1.indexOf(str2);\n    }\n\n    public static int indexOf(String str1, String str2) {\n      return str1.indexOf(str2);\n    }\n\n    public static int lastIndexOf(String str1, String str2) {\n      return str1.lastIndexOf(str2);\n    }\n\n    /** Substring */\n    public static String substr(String str, int start, int length) {\n      return str.substring(start, length);\n    }\n\n    public static String substr(String str, int start) {\n      return str.substring(start);\n    }\n\n    /**\n     * Returns the length of the given string. The length is equal to the number of <a\n     * href=\"Character.html#unicode\">Unicode code units</a> in the string.\n     *\n     * @param str String whose length is calculated.\n     * @return the length of the sequence of characters represented by this object.\n     */\n    public static int length(String str) {\n      return str.length();\n    }\n\n    /**\n     * This is synonym for \"length\".\n     *\n     * @see #length(String)\n     */\n    public static int strlen(String str) {\n      return str.length();\n    }\n\n    // regular expression matching\n\n    /**\n     * Compiles the given regular expression into a pattern.\n     *\n     * @param regex The expression to be compiled\n     * @throws PatternSyntaxException If the expression's syntax is invalid\n     */\n    public static Pattern regexp(String regex) {\n      return Pattern.compile(regex);\n    }\n\n    /**\n     * This is synonym for \"regexp\".\n     *\n     * @see #regexp(String)\n     */\n    public static Pattern pattern(String regex) {\n      return regexp(regex);\n    }\n\n    /**\n     * Compiles the given regular expression into a pattern with the given flags.\n     *\n     * @param regex The expression to be compiled\n     * @param flags Match flags, a bit mask that may include {@link Pattern#CASE_INSENSITIVE},\n     *     {@link Pattern#MULTILINE}, {@link Pattern#DOTALL}, {@link Pattern#UNICODE_CASE}, {@link\n     *     Pattern#CANON_EQ}, {@link Pattern#UNIX_LINES}, {@link Pattern#LITERAL} and {@link\n     *     Pattern#COMMENTS}\n     * @throws IllegalArgumentException If bit values other than those corresponding to the defined\n     *     match flags are set in <tt>flags</tt>\n     * @throws PatternSyntaxException If the expression's syntax is invalid\n     */\n    public static Pattern regexp(String regex, int flags) {\n      return Pattern.compile(regex, flags);\n    }\n\n    /**\n     * This is synonym for \"regexp\".\n     *\n     * @see #regexp(String, int)\n     */\n    public static Pattern pattern(String regex, int flags) {\n      return regexp(regex, flags);\n    }\n\n    /**\n     * Matches the given (precompiled) regular expression and attempts to match the given input\n     * against it.\n     */\n    public static boolean matches(Pattern regex, String input) {\n      return regex.matcher(input).matches();\n    }\n\n    /**\n     * Compiles the given regular expression and attempts to match the given input against it.\n     *\n     * <p>An invocation of this convenience method of the form\n     *\n     * <blockquote>\n     *\n     * <pre>\n     * Pattern.matches(regex, input);</pre>\n     *\n     * </blockquote>\n     *\n     * <p>behaves in exactly the same way as the expression\n     *\n     * <blockquote>\n     *\n     * <pre>\n     * Pattern.compile(regex).matcher(input).matches()</pre>\n     *\n     * </blockquote>\n     *\n     * <p>If a pattern is to be used multiple times, compiling it once and reusing it will be more\n     * efficient than invoking this method each time.\n     *\n     * @param regex The expression to be compiled\n     * @param input The character sequence to be matched\n     * @throws PatternSyntaxException If the expression's syntax is invalid\n     */\n    public static boolean matches(String regex, String input) {\n      return Pattern.matches(regex, input);\n    }\n\n    /**\n     * Returns a <tt>String</tt> object representing the specified boolean. If the specified boolean\n     * is <code>true</code>, then the string {@code \"true\"} will be returned, otherwise the string\n     * {@code \"false\"} will be returned.\n     *\n     * @param b the boolean to be converted\n     * @return the string representation of the specified <code>boolean</code>\n     */\n    public static String str(boolean b) {\n      return Boolean.toString(b);\n    }\n\n    /**\n     * Returns a <code>String</code> object representing the specified <code>char</code>. The result\n     * is a string of length 1 consisting solely of the specified <code>char</code>.\n     *\n     * @param c the <code>char</code> to be converted\n     * @return the string representation of the specified <code>char</code>\n     */\n    public static String str(char c) {\n      return Character.toString(c);\n    }\n\n    /**\n     * Returns a <code>String</code> object representing the specified integer. The argument is\n     * converted to signed decimal representation and returned as a string.\n     *\n     * @param i an integer to be converted.\n     * @return a string representation of the argument in base&nbsp;10.\n     */\n    public static String str(int i) {\n      return Integer.toString(i);\n    }\n\n    /**\n     * Returns a string representation of the integer argument as an unsigned integer in\n     * base&nbsp;16.\n     *\n     * <p>The unsigned integer value is the argument plus 2<sup>32</sup> if the argument is\n     * negative; otherwise, it is equal to the argument. This value is converted to a string of\n     * ASCII digits in hexadecimal (base&nbsp;16) with no extra leading <code>0</code>s. If the\n     * unsigned magnitude is zero, it is represented by a single zero character <code>'0'</code> (\n     * <code>'&#92;u0030'</code>); otherwise, the first character of the representation of the\n     * unsigned magnitude will not be the zero character. The following characters are used as\n     * hexadecimal digits:\n     *\n     * <blockquote>\n     *\n     * <pre>\n     * 0123456789abcdef\n     * </pre>\n     *\n     * </blockquote>\n     *\n     * These are the characters <code>'&#92;u0030'</code> through <code>'&#92;u0039'</code> and\n     * <code>'&#92;u0061'</code> through <code>'&#92;u0066'</code>.\n     *\n     * @param i an integer to be converted to a string.\n     * @return the string representation of the unsigned integer value represented by the argument\n     *     in hexadecimal (base&nbsp;16).\n     */\n    public static String toHexString(int i) {\n      return Integer.toHexString(i);\n    }\n\n    /**\n     * Returns a <code>String</code> object representing the specified <code>long</code>. The\n     * argument is converted to signed decimal representation and returned as a string.\n     *\n     * @param l a <code>long</code> to be converted.\n     * @return a string representation of the argument in base&nbsp;10.\n     */\n    public static String str(long l) {\n      return Long.toString(l);\n    }\n\n    /**\n     * Returns a string representation of the object. In general, the <code>toString</code> method\n     * returns a string that \"textually represents\" this object. The result should be a concise but\n     * informative representation that is easy for a person to read. For bootstrap classes, returns\n     * the result of calling Object.toString() override. For non-bootstrap classes, default\n     * toString() value [className@hashCode] is returned.\n     *\n     * @param obj the object whose string representation is returned\n     * @return a string representation of the given object.\n     */\n    public static String str(Object obj) {\n      if (obj == null) {\n        return \"null\";\n      } else if (obj instanceof String) {\n        return (String) obj;\n      } else if (obj.getClass().getClassLoader() == null) {\n        try {\n          return obj.toString();\n        } catch (NullPointerException e) {\n          // NPE can be thrown from inside the toString() method we have no control over\n          return \"null\";\n        }\n      } else {\n        return identityStr(obj);\n      }\n    }\n\n    public static String str(Object[] array) {\n      if (array == null) {\n        return \"null\";\n      }\n      StringBuilder buf = new StringBuilder();\n      buf.append('[');\n      for (int i = 0; i < array.length; i++) {\n        if (i > 0) {\n          buf.append(\", \");\n        }\n        buf.append(str(array[i]));\n      }\n      buf.append(']');\n      return buf.toString();\n    }\n\n    /**\n     * Returns a string representation of the <code>long</code> argument as an unsigned integer in\n     * base&nbsp;16.\n     *\n     * <p>The unsigned <code>long</code> value is the argument plus 2<sup>64</sup> if the argument\n     * is negative; otherwise, it is equal to the argument. This value is converted to a string of\n     * ASCII digits in hexadecimal (base&nbsp;16) with no extra leading <code>0</code>s. If the\n     * unsigned magnitude is zero, it is represented by a single zero character <code>'0'</code> (\n     * <code>'&#92;u0030'</code>); otherwise, the first character of the representation of the\n     * unsigned magnitude will not be the zero character. The following characters are used as\n     * hexadecimal digits:\n     *\n     * <blockquote>\n     *\n     * <pre>\n     * 0123456789abcdef\n     * </pre>\n     *\n     * </blockquote>\n     *\n     * These are the characters <code>'&#92;u0030'</code> through <code>'&#92;u0039'</code> and\n     * <code>'&#92;u0061'</code> through <code>'&#92;u0066'</code>.\n     *\n     * @param l a <code>long</code> to be converted to a string.\n     * @return the string representation of the unsigned <code>long</code> value represented by the\n     *     argument in hexadecimal (base&nbsp;16).\n     */\n    public static String toHexString(long l) {\n      return Long.toHexString(l);\n    }\n\n    /**\n     * Returns a string representation of the <code>float</code> argument. All characters mentioned\n     * below are ASCII characters.\n     *\n     * <ul>\n     *   <li>If the argument is NaN, the result is the string &quot;<code>NaN</code>&quot;.\n     *   <li>Otherwise, the result is a string that represents the sign and magnitude (absolute\n     *       value) of the argument. If the sign is negative, the first character of the result is '\n     *       <code>-</code>' (<code>'&#92;u002D'</code>); if the sign is positive, no sign character\n     *       appears in the result. As for the magnitude <i>m</i>:\n     *       <ul>\n     *         <li>If <i>m</i> is infinity, it is represented by the characters <code>\"Infinity\"\n     *             </code>; thus, positive infinity produces the result <code>\"Infinity\"</code> and\n     *             negative infinity produces the result <code>\"-Infinity\"</code>.\n     *         <li>If <i>m</i> is zero, it is represented by the characters <code>\"0.0\"</code>;\n     *             thus, negative zero produces the result <code>\"-0.0\"</code> and positive zero\n     *             produces the result <code>\"0.0\"</code>.\n     *         <li>If <i>m</i> is greater than or equal to 10<sup>-3</sup> but less than\n     *             10<sup>7</sup>, then it is represented as the integer part of <i>m</i>, in\n     *             decimal form with no leading zeroes, followed by '<code>.</code>' (<code>\n     *             '&#92;u002E'</code>), followed by one or more decimal digits representing the\n     *             fractional part of <i>m</i>.\n     *         <li>If <i>m</i> is less than 10<sup>-3</sup> or greater than or equal to\n     *             10<sup>7</sup>, then it is represented in so-called \"computerized scientific\n     *             notation.\" Let <i>n</i> be the unique integer such that 10<sup><i>n</i>\n     *             </sup>&lt;= <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the\n     *             mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so that 1\n     *             &lt;= <i>a</i> &lt; 10. The magnitude is then represented as the integer part of\n     *             <i>a</i>, as a single decimal digit, followed by '<code>.</code>' (<code>\n     *             '&#92;u002E'</code>), followed by decimal digits representing the fractional part\n     *             of <i>a</i>, followed by the letter '<code>E</code>' (<code>'&#92;u0045'</code>),\n     *             followed by a representation of <i>n</i> as a decimal integer, as produced by the\n     *             method <code>{@link\n     *      java.lang.Integer#toString(int)}</code>.\n     *       </ul>\n     * </ul>\n     *\n     * How many digits must be printed for the fractional part of <i>m</i> or <i>a</i>? There must\n     * be at least one digit to represent the fractional part, and beyond that as many, but only as\n     * many, more digits as are needed to uniquely distinguish the argument value from adjacent\n     * values of type <code>float</code>. That is, suppose that <i>x</i> is the exact mathematical\n     * value represented by the decimal representation produced by this method for a finite nonzero\n     * argument <i>f</i>. Then <i>f</i> must be the <code>float</code> value nearest to <i>x</i>;\n     * or, if two <code>float</code> values are equally close to <i>x</i>, then <i>f</i> must be one\n     * of them and the least significant bit of the significand of <i>f</i> must be <code>0</code>.\n     *\n     * <p>\n     *\n     * @param f the float to be converted.\n     * @return a string representation of the argument.\n     */\n    public static String str(float f) {\n      return Float.toString(f);\n    }\n\n    /**\n     * Returns a string representation of the <code>double</code> argument. All characters mentioned\n     * below are ASCII characters.\n     *\n     * <ul>\n     *   <li>If the argument is NaN, the result is the string &quot;<code>NaN</code>&quot;.\n     *   <li>Otherwise, the result is a string that represents the sign and magnitude (absolute\n     *       value) of the argument. If the sign is negative, the first character of the result is '\n     *       <code>-</code>' (<code>'&#92;u002D'</code>); if the sign is positive, no sign character\n     *       appears in the result. As for the magnitude <i>m</i>:\n     *       <ul>\n     *         <li>If <i>m</i> is infinity, it is represented by the characters <code>\"Infinity\"\n     *             </code>; thus, positive infinity produces the result <code>\"Infinity\"</code> and\n     *             negative infinity produces the result <code>\"-Infinity\"</code>.\n     *         <li>If <i>m</i> is zero, it is represented by the characters <code>\"0.0\"</code>;\n     *             thus, negative zero produces the result <code>\"-0.0\"</code> and positive zero\n     *             produces the result <code>\"0.0\"</code>.\n     *         <li>If <i>m</i> is greater than or equal to 10<sup>-3</sup> but less than\n     *             10<sup>7</sup>, then it is represented as the integer part of <i>m</i>, in\n     *             decimal form with no leading zeroes, followed by '<code>.</code>' (<code>\n     *             '&#92;u002E'</code>), followed by one or more decimal digits representing the\n     *             fractional part of <i>m</i>.\n     *         <li>If <i>m</i> is less than 10<sup>-3</sup> or greater than or equal to\n     *             10<sup>7</sup>, then it is represented in so-called \"computerized scientific\n     *             notation.\" Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup>\n     *             &lt;= <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the\n     *             mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so that 1\n     *             &lt;= <i>a</i> &lt; 10. The magnitude is then represented as the integer part of\n     *             <i>a</i>, as a single decimal digit, followed by '<code>.</code>' (<code>\n     *             '&#92;u002E'</code>), followed by decimal digits representing the fractional part\n     *             of <i>a</i>, followed by the letter '<code>E</code>' (<code>'&#92;u0045'</code>),\n     *             followed by a representation of <i>n</i> as a decimal integer, as produced by the\n     *             method {@link Integer#toString(int)}.\n     *       </ul>\n     * </ul>\n     *\n     * How many digits must be printed for the fractional part of <i>m</i> or <i>a</i>? There must\n     * be at least one digit to represent the fractional part, and beyond that as many, but only as\n     * many, more digits as are needed to uniquely distinguish the argument value from adjacent\n     * values of type <code>double</code>. That is, suppose that <i>x</i> is the exact mathematical\n     * value represented by the decimal representation produced by this method for a finite nonzero\n     * argument <i>d</i>. Then <i>d</i> must be the <code>double</code> value nearest to <i>x</i>;\n     * or if two <code>double</code> values are equally close to <i>x</i>, then <i>d</i> must be one\n     * of them and the least significant bit of the significand of <i>d</i> must be <code>0</code>.\n     *\n     * <p>\n     *\n     * @param d the <code>double</code> to be converted.\n     * @return a string representation of the argument.\n     */\n    public static String str(double d) {\n      return Double.toString(d);\n    }\n\n    /**\n     * Safely creates a new instance of an appendable string buffer <br>\n     *\n     * @param threadSafe Specifies whether the buffer should be thread safe\n     * @return Returns either {@linkplain StringBuilder} or {@linkplain StringBuffer} instance\n     *     depending on whether the instance is required to be thread safe or not, respectively.\n     * @since 1.2\n     */\n    public static Appendable newStringBuilder(boolean threadSafe) {\n      return BTraceRuntime.newStringBuilder(threadSafe);\n    }\n\n    /**\n     * Safely creates a new instance of an appendable string buffer <br>\n     * The buffer will not be thread safe.\n     *\n     * @return Returns a new instance of {@linkplain StringBuilder} class\n     * @since 1.2\n     */\n    public static Appendable newStringBuilder() {\n      return BTraceRuntime.newStringBuilder();\n    }\n\n    /**\n     * Appends a string to an appendable buffer created by {@linkplain\n     * BTraceUtils.Strings#newStringBuilder()}\n     *\n     * @param buffer The appendable buffer to append to\n     * @param strToAppend The string to append\n     * @return Returns the same appendable buffer instance\n     * @since 1.2\n     */\n    public static Appendable append(Appendable buffer, String strToAppend) {\n      return BTraceRuntime.append(buffer, strToAppend);\n    }\n\n    /**\n     * Checks the length of an appendable buffer created by {@linkplain\n     * BTraceUtils.Strings#newStringBuilder()}\n     *\n     * @param buffer The appendable buffer instance\n     * @return Returns the length of the text contained by the buffer\n     * @since 1.2\n     */\n    public static int length(Appendable buffer) {\n      return BTraceRuntime.length(buffer);\n    }\n  }\n\n  /*\n   * Wraps the numbers related BTrace utility methods\n   * @since 1.2\n   */\n  public static class Numbers {\n    /**\n     * Returns a <code>double</code> value with a positive sign, greater than or equal to <code>0.0\n     * </code> and less than <code>1.0</code>. Returned values are chosen pseudorandomly with\n     * (approximately) uniform distribution from that range.\n     */\n    public static double random() {\n      return Math.random();\n    }\n\n    /**\n     * Returns the natural logarithm (base <i>e</i>) of a <code>double</code> value. Special cases:\n     *\n     * <ul>\n     *   <li>If the argument is NaN or less than zero, then the result is NaN.\n     *   <li>If the argument is positive infinity, then the result is positive infinity.\n     *   <li>If the argument is positive zero or negative zero, then the result is negative\n     *       infinity.\n     * </ul>\n     *\n     * <p>The computed result must be within 1 ulp of the exact result. Results must be\n     * semi-monotonic.\n     *\n     * @param a a value\n     * @return the value ln&nbsp;<code>a</code>, the natural logarithm of <code>a</code>.\n     */\n    public static strictfp double log(double a) {\n      return Math.log(a);\n    }\n\n    /**\n     * Returns the base 10 logarithm of a <code>double</code> value. Special cases:\n     *\n     * <ul>\n     *   <li>If the argument is NaN or less than zero, then the result is NaN.\n     *   <li>If the argument is positive infinity, then the result is positive infinity.\n     *   <li>If the argument is positive zero or negative zero, then the result is negative\n     *       infinity.\n     *   <li>If the argument is equal to 10<sup><i>n</i></sup> for integer <i>n</i>, then the result\n     *       is <i>n</i>.\n     * </ul>\n     *\n     * <p>The computed result must be within 1 ulp of the exact result. Results must be\n     * semi-monotonic.\n     *\n     * @param a a value\n     * @return the base 10 logarithm of <code>a</code>.\n     */\n    public static strictfp double log10(double a) {\n      return Math.log10(a);\n    }\n\n    /**\n     * Returns Euler's number <i>e</i> raised to the power of a <code>double</code> value. Special\n     * cases:\n     *\n     * <ul>\n     *   <li>If the argument is NaN, the result is NaN.\n     *   <li>If the argument is positive infinity, then the result is positive infinity.\n     *   <li>If the argument is negative infinity, then the result is positive zero.\n     * </ul>\n     *\n     * <p>The computed result must be within 1 ulp of the exact result. Results must be\n     * semi-monotonic.\n     *\n     * @param a the exponent to raise <i>e</i> to.\n     * @return the value <i>e</i><sup><code>a</code></sup>, where <i>e</i> is the base of the\n     *     natural logarithms.\n     */\n    public static strictfp double exp(double a) {\n      return Math.exp(a);\n    }\n\n    /**\n     * Returns <code>true</code> if the specified number is a Not-a-Number (NaN) value, <code>false\n     * </code> otherwise.\n     *\n     * @param d the value to be tested.\n     * @return <code>true</code> if the value of the argument is NaN; <code>false</code> otherwise.\n     */\n    public static boolean isNaN(double d) {\n      return Double.isNaN(d);\n    }\n\n    /**\n     * Returns <code>true</code> if the specified number is a Not-a-Number (NaN) value, <code>false\n     * </code> otherwise.\n     *\n     * @param f the value to be tested.\n     * @return <code>true</code> if the value of the argument is NaN; <code>false</code> otherwise.\n     */\n    public static boolean isNaN(float f) {\n      return Float.isNaN(f);\n    }\n\n    /**\n     * Returns <code>true</code> if the specified number is infinitely large in magnitude, <code>\n     * false</code> otherwise.\n     *\n     * @param d the value to be tested.\n     * @return <code>true</code> if the value of the argument is positive infinity or negative\n     *     infinity; <code>false</code> otherwise.\n     */\n    public static boolean isInfinite(double d) {\n      return Double.isInfinite(d);\n    }\n\n    /**\n     * Returns <code>true</code> if the specified number is infinitely large in magnitude, <code>\n     * false</code> otherwise.\n     *\n     * @param f the value to be tested.\n     * @return <code>true</code> if the value of the argument is positive infinity or negative\n     *     infinity; <code>false</code> otherwise.\n     */\n    public static boolean isInfinite(float f) {\n      return Float.isInfinite(f);\n    }\n\n    // string parsing methods\n\n    /**\n     * Parses the string argument as a boolean. The <code>boolean</code> returned represents the\n     * value <code>true</code> if the string argument is not <code>null</code> and is equal,\n     * ignoring case, to the string {@code \"true\"}.\n     *\n     * <p>Example: {@code Boolean.parseBoolean(\"True\")} returns <tt>true</tt>.<br>\n     * Example: {@code Boolean.parseBoolean(\"yes\")} returns <tt>false</tt>.\n     *\n     * @param s the <code>String</code> containing the boolean representation to be parsed\n     * @return the boolean represented by the string argument\n     */\n    public static boolean parseBoolean(String s) {\n      return Boolean.parseBoolean(s);\n    }\n\n    /**\n     * Parses the string argument as a signed decimal <code>byte</code>. The characters in the\n     * string must all be decimal digits, except that the first character may be an ASCII minus sign\n     * <code>'-'</code> (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting\n     * <code>byte</code> value is returned.\n     *\n     * @param s a <code>String</code> containing the <code>byte</code> representation to be parsed\n     * @return the <code>byte</code> value represented by the argument in decimal\n     */\n    public static byte parseByte(String s) {\n      return Byte.parseByte(s);\n    }\n\n    /**\n     * Parses the string argument as a signed decimal <code>short</code>. The characters in the\n     * string must all be decimal digits, except that the first character may be an ASCII minus sign\n     * <code>'-'</code> (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting\n     * <code>short</code> value is returned.\n     *\n     * @param s a <code>String</code> containing the <code>short</code> representation to be parsed\n     * @return the <code>short</code> value represented by the argument in decimal.\n     */\n    public static short parseShort(String s) {\n      return Short.parseShort(s);\n    }\n\n    /**\n     * Parses the string argument as a signed decimal integer. The characters in the string must all\n     * be decimal digits, except that the first character may be an ASCII minus sign <code>'-'\n     * </code> (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting integer value\n     * is returned.\n     *\n     * @param s a <code>String</code> containing the <code>int</code> representation to be parsed\n     * @return the integer value represented by the argument in decimal.\n     */\n    public static int parseInt(String s) {\n      return Integer.parseInt(s);\n    }\n\n    /**\n     * Parses the string argument as a signed decimal <code>long</code>. The characters in the\n     * string must all be decimal digits, except that the first character may be an ASCII minus sign\n     * <code>'-'</code> (<code>&#92;u002D'</code>) to indicate a negative value. The resulting\n     * <code>long</code> value is returned.\n     *\n     * <p>Note that neither the character <code>L</code> (<code>'&#92;u004C'</code>) nor <code>l\n     * </code> (<code>'&#92;u006C'</code>) is permitted to appear at the end of the string as a type\n     * indicator, as would be permitted in Java programming language source code.\n     *\n     * @param s a <code>String</code> containing the <code>long</code> representation to be parsed\n     * @return the <code>long</code> represented by the argument in decimal.\n     */\n    public static long parseLong(String s) {\n      return Long.parseLong(s);\n    }\n\n    /**\n     * Returns a new <code>float</code> initialized to the value represented by the specified <code>\n     * String</code>, as performed by the <code>valueOf</code> method of class <code>Float</code>.\n     *\n     * @param s the string to be parsed.\n     * @return the <code>float</code> value represented by the string argument.\n     */\n    public static float parseFloat(String s) {\n      return Float.parseFloat(s);\n    }\n\n    /**\n     * Returns a new <code>double</code> initialized to the value represented by the specified\n     * <code>String</code>, as performed by the <code>valueOf</code> methcod of class <code>Double\n     * </code>.\n     *\n     * @param s the string to be parsed.\n     * @return the <code>double</code> value represented by the string argument.\n     */\n    public static double parseDouble(String s) {\n      return Double.parseDouble(s);\n    }\n\n    // boxing methods\n\n    /**\n     * Returns a <tt>Boolean</tt> instance representing the specified <tt>boolean</tt> value. If the\n     * specified <tt>boolean</tt> value is <tt>true</tt>, this method returns <tt>Boolean.TRUE</tt>;\n     * if it is <tt>false</tt>, this method returns <tt>Boolean.FALSE</tt>.\n     *\n     * @param b a boolean value.\n     * @return a <tt>Boolean</tt> instance representing <tt>b</tt>.\n     */\n    public static Boolean box(boolean b) {\n      return b;\n    }\n\n    /**\n     * Returns a <tt>Character</tt> instance representing the specified <tt>char</tt> value.\n     *\n     * @param c a char value.\n     * @return a <tt>Character</tt> instance representing <tt>c</tt>.\n     */\n    public static Character box(char c) {\n      return c;\n    }\n\n    /**\n     * Returns a <tt>Byte</tt> instance representing the specified <tt>byte</tt> value.\n     *\n     * @param b a byte value.\n     * @return a <tt>Byte</tt> instance representing <tt>b</tt>.\n     */\n    public static Byte box(byte b) {\n      return b;\n    }\n\n    /**\n     * Returns a <tt>Short</tt> instance representing the specified <tt>short</tt> value.\n     *\n     * @param s a short value.\n     * @return a <tt>Short</tt> instance representing <tt>s</tt>.\n     */\n    public static Short box(short s) {\n      return s;\n    }\n\n    /**\n     * Returns a <tt>Integer</tt> instance representing the specified <tt>int</tt> value.\n     *\n     * @param i an <code>int</code> value.\n     * @return a <tt>Integer</tt> instance representing <tt>i</tt>.\n     */\n    public static Integer box(int i) {\n      return i;\n    }\n\n    /**\n     * Returns a <tt>Long</tt> instance representing the specified <tt>long</tt> value.\n     *\n     * @param l a long value.\n     * @return a <tt>Long</tt> instance representing <tt>l</tt>.\n     */\n    public static Long box(long l) {\n      return l;\n    }\n\n    /**\n     * Returns a <tt>Float</tt> instance representing the specified <tt>float</tt> value.\n     *\n     * @param f a float value.\n     * @return a <tt>Float</tt> instance representing <tt>f</tt>.\n     */\n    public static Float box(float f) {\n      return f;\n    }\n\n    /**\n     * Returns a <tt>Double</tt> instance representing the specified <tt>double</tt> value.\n     *\n     * @param d a double value.\n     * @return a <tt>Double</tt> instance representing <tt>d</tt>.\n     */\n    public static Double box(double d) {\n      return d;\n    }\n\n    // unboxing methods\n\n    /**\n     * Returns the value of the given <tt>Boolean</tt> object as a boolean primitive.\n     *\n     * @param b the Boolean object whose value is returned.\n     * @return the primitive <code>boolean</code> value of the object.\n     */\n    public static boolean unbox(Boolean b) {\n      return b;\n    }\n\n    /**\n     * Returns the value of the given <tt>Character</tt> object as a char primitive.\n     *\n     * @param ch the Character object whose value is returned.\n     * @return the primitive <code>char</code> value of the object.\n     */\n    public static char unbox(Character ch) {\n      return ch;\n    }\n\n    /**\n     * Returns the value of the specified Byte as a <code>byte</code>.\n     *\n     * @param b Byte that is unboxed\n     * @return the byte value represented by the <code>Byte</code>.\n     */\n    public static byte unbox(Byte b) {\n      return b;\n    }\n\n    /**\n     * Returns the short value represented by <code>Short</code>.\n     *\n     * @param s Short that is unboxed.\n     * @return the short value represented by the <code>Short</code>.\n     */\n    public static short unbox(Short s) {\n      return s;\n    }\n\n    /**\n     * Returns the value of represented by <code>Integer</code>.\n     *\n     * @param i Integer that is unboxed.\n     * @return the int value represented by the <code>Integer</code>.\n     */\n    public static int unbox(Integer i) {\n      return i;\n    }\n\n    /**\n     * Returns the long value represented by the specified <code>Long</code>.\n     *\n     * @param l Long to be unboxed.\n     * @return the long value represented by the <code>Long</code>.\n     */\n    public static long unbox(Long l) {\n      return l;\n    }\n\n    /**\n     * Returns the float value represented by the specified <code>Float</code>.\n     *\n     * @param f Float to be unboxed.\n     * @return the float value represented by the <code>Float</code>.\n     */\n    public static float unbox(Float f) {\n      return f;\n    }\n\n    /**\n     * Returns the double value represented by the specified <code>Double</code>.\n     *\n     * @param d Double to be unboxed.\n     */\n    public static double unbox(Double d) {\n      return d;\n    }\n  }\n\n  /*\n   * Wraps the time related BTrace utility methods\n   * @since 1.2\n   */\n  public static class Time {\n    /**\n     * Returns the current time in milliseconds. Note that while the unit of time of the return\n     * value is a millisecond, the granularity of the value depends on the underlying operating\n     * system and may be larger. For example, many operating systems measure time in units of tens\n     * of milliseconds.\n     *\n     * @return the difference, measured in milliseconds, between the current time and midnight,\n     *     January 1, 1970 UTC.\n     */\n    public static long millis() {\n      return java.lang.System.currentTimeMillis();\n    }\n\n    /**\n     * Returns the current value of the most precise available system timer, in nanoseconds.\n     *\n     * <p>This method can only be used to measure elapsed time and is not related to any other\n     * notion of system or wall-clock time. The value returned represents nanoseconds since some\n     * fixed but arbitrary time (perhaps in the future, so values may be negative). This method\n     * provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees are\n     * made about how frequently values change. Differences in successive calls that span greater\n     * than approximately 292 years (2<sup>63</sup> nanoseconds) will not accurately compute elapsed\n     * time due to numerical overflow.\n     *\n     * @return The current value of the system timer, in nanoseconds.\n     */\n    public static long nanos() {\n      return java.lang.System.nanoTime();\n    }\n\n    /**\n     * Generates a string timestamp (current date&amp;time)\n     *\n     * @param format The format to be used - see {@linkplain SimpleDateFormat}\n     * @return Returns a string representing current date&amp;time\n     * @since 1.1\n     */\n    public static String timestamp(String format) {\n      return new SimpleDateFormat(format).format(Calendar.getInstance().getTime());\n    }\n\n    /**\n     * Generates a string timestamp (current date&amp;time) in the default system format\n     *\n     * @return Returns a string representing current date&amp;time\n     * @since 1.1\n     */\n    public static String timestamp() {\n      return new SimpleDateFormat().format(Calendar.getInstance().getTime());\n    }\n  }\n\n  /*\n   * Wraps the collections related BTrace utility methods\n   * @since 1.2\n   */\n  @SuppressWarnings(\"EmptyMethod\")\n  public static class Collections {\n    // Create a new map\n    public static <K, V> Map<K, V> newHashMap() {\n      return BTraceRuntime.newHashMap();\n    }\n\n    public static <K, V> Map<K, V> newWeakMap() {\n      return BTraceRuntime.newWeakMap();\n    }\n\n    public static <V> Deque<V> newDeque() {\n      return BTraceRuntime.newDeque();\n    }\n\n    public static <K, V> void putAll(Map<K, V> src, Map<K, V> dst) {\n      BTraceRuntime.putAll(src, dst);\n    }\n\n    public static <K, V> void copy(Map<K, V> src, Map<K, V> dst) {\n      BTraceRuntime.copy(src, dst);\n    }\n\n    public static <V> void copy(Collection<V> src, Collection<V> dst) {}\n\n    // get a particular item from a Map\n    public static <K, V> V get(Map<K, V> map, K key) {\n      return BTraceRuntime.get(map, key);\n    }\n\n    // check whether an item exists\n    public static <K, V> boolean containsKey(Map<K, V> map, K key) {\n      return BTraceRuntime.containsKey(map, key);\n    }\n\n    public static <K, V> boolean containsValue(Map<K, V> map, V value) {\n      return BTraceRuntime.containsValue(map, value);\n    }\n\n    // put a particular item into a Map\n    public static <K, V> V put(Map<K, V> map, K key, V value) {\n      return BTraceRuntime.put(map, key, value);\n    }\n\n    // remove a particular item from a Map\n    public static <K, V> V remove(Map<K, V> map, K key) {\n      return BTraceRuntime.remove(map, key);\n    }\n\n    // clear all items from a Map\n    public static <K, V> void clear(Map<K, V> map) {\n      BTraceRuntime.clear(map);\n    }\n\n    // return the size of a Map\n    public static <K, V> int size(Map<K, V> map) {\n      return BTraceRuntime.size(map);\n    }\n\n    public static <K, V> boolean isEmpty(Map<K, V> map) {\n      return BTraceRuntime.isEmpty(map);\n    }\n\n    // operations on collections\n    public static <E> int size(Collection<E> coll) {\n      return BTraceRuntime.size(coll);\n    }\n\n    public static <E> boolean isEmpty(Collection<E> coll) {\n      return BTraceRuntime.isEmpty(coll);\n    }\n\n    public static <E> boolean contains(Collection<E> coll, Object obj) {\n      return BTraceRuntime.contains(coll, obj);\n    }\n\n    public static boolean contains(Object[] array, Object value) {\n      for (Object each : array) {\n        if (compare(each, value)) {\n          return true;\n        }\n      }\n      return false;\n    }\n\n    public static <E> Object[] toArray(Collection<E> collection) {\n      return BTraceRuntime.toArray(collection);\n    }\n\n    // operations on Deque\n    public static <V> void push(Deque<V> queue, V value) {\n      BTraceRuntime.push(queue, value);\n    }\n\n    public static <V> V poll(Deque<V> queue) {\n      return BTraceRuntime.poll(queue);\n    }\n\n    public static <V> V peek(Deque<V> queue) {\n      return BTraceRuntime.peek(queue);\n    }\n\n    public static <V> void addLast(Deque<V> queue, V value) {\n      BTraceRuntime.addLast(queue, value);\n    }\n\n    public static <V> V peekFirst(Deque<V> queue) {\n      return BTraceRuntime.peekFirst(queue);\n    }\n\n    public static <V> V peekLast(Deque<V> queue) {\n      return BTraceRuntime.peekLast(queue);\n    }\n\n    public static <V> V removeLast(Deque<V> queue) {\n      return BTraceRuntime.removeLast(queue);\n    }\n\n    public static <V> V removeFirst(Deque<V> queue) {\n      return BTraceRuntime.removeFirst(queue);\n    }\n  }\n\n  /*\n   * Wraps the atomicity related BTrace utility methods\n   * @since 1.2\n   */\n  public static class Atomic {\n    /**\n     * Creates a new AtomicInteger with the given initial value.\n     *\n     * @param initialValue the initial value\n     */\n    public static AtomicInteger newAtomicInteger(int initialValue) {\n      return BTraceRuntime.newAtomicInteger(initialValue);\n    }\n\n    /**\n     * Gets the current value of the given AtomicInteger.\n     *\n     * @param ai AtomicInteger whose value is returned.\n     * @return the current value\n     */\n    public static int get(AtomicInteger ai) {\n      return BTraceRuntime.get(ai);\n    }\n\n    /**\n     * Sets to the given value to the given AtomicInteger.\n     *\n     * @param ai AtomicInteger whose value is set.\n     * @param newValue the new value\n     */\n    public static void set(AtomicInteger ai, int newValue) {\n      BTraceRuntime.set(ai, newValue);\n    }\n\n    /**\n     * Eventually sets to the given value to the given AtomicInteger.\n     *\n     * @param ai AtomicInteger whose value is lazily set.\n     * @param newValue the new value\n     */\n    public static void lazySet(AtomicInteger ai, int newValue) {\n      BTraceRuntime.lazySet(ai, newValue);\n    }\n\n    /**\n     * Atomically sets the value of given AtomitInteger to the given updated value if the current\n     * value {@code ==} the expected value.\n     *\n     * @param ai AtomicInteger whose value is compared and set.\n     * @param expect the expected value\n     * @param update the new value\n     * @return true if successful. False return indicates that the actual value was not equal to the\n     *     expected value.\n     */\n    public static boolean compareAndSet(AtomicInteger ai, int expect, int update) {\n      return BTraceRuntime.compareAndSet(ai, expect, update);\n    }\n\n    /**\n     * Atomically sets the value to the given updated value if the current value {@code ==} the\n     * expected value.\n     *\n     * <p>May <a href=\"package-summary.html#Spurious\">fail spuriously</a> and does not provide\n     * ordering guarantees, so is only rarely an appropriate alternative to {@code compareAndSet}.\n     *\n     * @param ai AtomicInteger whose value is weakly compared and set.\n     * @param expect the expected value\n     * @param update the new value\n     * @return true if successful.\n     */\n    public static boolean weakCompareAndSet(AtomicInteger ai, int expect, int update) {\n      return BTraceRuntime.weakCompareAndSet(ai, expect, update);\n    }\n\n    /**\n     * Atomically increments by one the current value of given AtomicInteger.\n     *\n     * @param ai AtomicInteger that is incremented.\n     * @return the previous value\n     */\n    public static int getAndIncrement(AtomicInteger ai) {\n      return BTraceRuntime.getAndIncrement(ai);\n    }\n\n    /**\n     * Atomically decrements by one the current value of given AtomicInteger.\n     *\n     * @param ai AtomicInteger that is decremented.\n     * @return the previous value\n     */\n    public static int getAndDecrement(AtomicInteger ai) {\n      return BTraceRuntime.getAndDecrement(ai);\n    }\n\n    /**\n     * Atomically increments by one the current value of given AtomicInteger.\n     *\n     * @param ai AtomicInteger that is incremented.\n     * @return the updated value\n     */\n    public static int incrementAndGet(AtomicInteger ai) {\n      return BTraceRuntime.incrementAndGet(ai);\n    }\n\n    /**\n     * Atomically decrements by one the current value of given AtomicInteger.\n     *\n     * @param ai AtomicInteger whose value is decremented.\n     * @return the updated value\n     */\n    public static int decrementAndGet(AtomicInteger ai) {\n      return BTraceRuntime.decrementAndGet(ai);\n    }\n\n    /**\n     * Atomically adds the given value to the current value.\n     *\n     * @param ai AtomicInteger whose value is added to.\n     * @param delta the value to add\n     * @return the previous value\n     */\n    public static int getAndAdd(AtomicInteger ai, int delta) {\n      return BTraceRuntime.getAndAdd(ai, delta);\n    }\n\n    /**\n     * Atomically adds the given value to the current value.\n     *\n     * @param ai AtomicInteger whose value is added to.\n     * @param delta the value to add\n     * @return the updated value\n     */\n    public static int addAndGet(AtomicInteger ai, int delta) {\n      return BTraceRuntime.addAndGet(ai, delta);\n    }\n\n    /**\n     * Atomically sets to the given value and returns the old value.\n     *\n     * @param ai AtomicInteger whose value is set.\n     * @param newValue the new value\n     * @return the previous value\n     */\n    public static int getAndSet(AtomicInteger ai, int newValue) {\n      return BTraceRuntime.getAndSet(ai, newValue);\n    }\n\n    /**\n     * Creates a new AtomicLong with the given initial value.\n     *\n     * @param initialValue the initial value\n     */\n    public static AtomicLong newAtomicLong(long initialValue) {\n      return BTraceRuntime.newAtomicLong(initialValue);\n    }\n\n    /**\n     * Gets the current value the given AtomicLong.\n     *\n     * @param al AtomicLong whose value is returned.\n     * @return the current value\n     */\n    public static long get(AtomicLong al) {\n      return BTraceRuntime.get(al);\n    }\n\n    /**\n     * Sets to the given value.\n     *\n     * @param al AtomicLong whose value is set.\n     * @param newValue the new value\n     */\n    public static void set(AtomicLong al, long newValue) {\n      BTraceRuntime.set(al, newValue);\n    }\n\n    /**\n     * Eventually sets to the given value to the given AtomicLong.\n     *\n     * @param al AtomicLong whose value is set.\n     * @param newValue the new value\n     */\n    public static void lazySet(AtomicLong al, long newValue) {\n      BTraceRuntime.lazySet(al, newValue);\n    }\n\n    /**\n     * Atomically sets the value to the given updated value if the current value {@code ==} the\n     * expected value.\n     *\n     * @param al AtomicLong whose value is compared and set.\n     * @param expect the expected value\n     * @param update the new value\n     * @return true if successful. False return indicates that the actual value was not equal to the\n     *     expected value.\n     */\n    public static boolean compareAndSet(AtomicLong al, long expect, long update) {\n      return BTraceRuntime.compareAndSet(al, expect, update);\n    }\n\n    /**\n     * Atomically sets the value to the given updated value if the current value {@code ==} the\n     * expected value.\n     *\n     * <p>May fail spuriously and does not provide ordering guarantees, so is only rarely an\n     * appropriate alternative to {@code compareAndSet}.\n     *\n     * @param al AtomicLong whose value is compared and set.\n     * @param expect the expected value\n     * @param update the new value\n     * @return true if successful.\n     */\n    public static boolean weakCompareAndSet(AtomicLong al, long expect, long update) {\n      return BTraceRuntime.weakCompareAndSet(al, expect, update);\n    }\n\n    /**\n     * Atomically increments by one the current value.\n     *\n     * @param al AtomicLong whose value is incremented.\n     * @return the previous value\n     */\n    public static long getAndIncrement(AtomicLong al) {\n      return BTraceRuntime.getAndIncrement(al);\n    }\n\n    /**\n     * Atomically decrements by one the current value.\n     *\n     * @param al AtomicLong whose value is decremented.\n     * @return the previous value\n     */\n    public static long getAndDecrement(AtomicLong al) {\n      return BTraceRuntime.getAndDecrement(al);\n    }\n\n    /**\n     * Atomically increments by one the current value.\n     *\n     * @param al AtomicLong whose value is incremented.\n     * @return the updated value\n     */\n    public static long incrementAndGet(AtomicLong al) {\n      return BTraceRuntime.incrementAndGet(al);\n    }\n\n    /**\n     * Atomically decrements by one the current value.\n     *\n     * @param al AtomicLong whose value is decremented.\n     * @return the updated value\n     */\n    public static long decrementAndGet(AtomicLong al) {\n      return BTraceRuntime.decrementAndGet(al);\n    }\n\n    /**\n     * Atomically adds the given value to the current value.\n     *\n     * @param al AtomicLong whose value is added to.\n     * @param delta the value to add\n     * @return the previous value\n     */\n    public static long getAndAdd(AtomicLong al, long delta) {\n      return BTraceRuntime.getAndAdd(al, delta);\n    }\n\n    /**\n     * Atomically adds the given value to the current value.\n     *\n     * @param al AtomicLong whose value is added to\n     * @param delta the value to add\n     * @return the updated value\n     */\n    public static long addAndGet(AtomicLong al, long delta) {\n      return BTraceRuntime.addAndGet(al, delta);\n    }\n\n    /**\n     * Atomically sets to the given value and returns the old value.\n     *\n     * @param al AtomicLong that is set.\n     * @param newValue the new value\n     * @return the previous value\n     */\n    public static long getAndSet(AtomicLong al, long newValue) {\n      return BTraceRuntime.getAndSet(al, newValue);\n    }\n  }\n\n  /**\n   * Profiling support. It is a highly specialized aggregation (therefore not included in the\n   * generic aggregations support) which is able to calculate clean self time spent in\n   * hierarchically called methods (or bigger parts of code)\n   */\n  public static class Profiling {\n    /**\n     * Creates a new {@linkplain Profiler} instance\n     *\n     * @return A new {@linkplain Profiler} instance\n     */\n    public static Profiler newProfiler() {\n      return BTraceRuntime.newProfiler();\n    }\n\n    /**\n     * Creates a new {@linkplain Profiler} instance with the specified expected count of the\n     * distinct methods to be recorded.\n     *\n     * @param expectedBlockCnt The expected count of the distinct blocks to be recorded.\n     * @return Returns a new {@linkplain Profiler} instance\n     */\n    public static Profiler newProfiler(int expectedBlockCnt) {\n      return BTraceRuntime.newProfiler(expectedBlockCnt);\n    }\n\n    /**\n     * Records the entry to a particular code block\n     *\n     * @param profiler The {@linkplain Profiler} instance to use\n     * @param blockName The block identifier\n     */\n    public static void recordEntry(Profiler profiler, String blockName) {\n      BTraceRuntime.recordEntry(profiler, blockName);\n    }\n\n    /**\n     * Records the exit out of a particular code block\n     *\n     * @param profiler The {@linkplain Profiler} instance to use\n     * @param blockName The block identifier\n     * @param duration The time spent in the mentioned block\n     */\n    public static void recordExit(Profiler profiler, String blockName, long duration) {\n      BTraceRuntime.recordExit(profiler, blockName, duration);\n    }\n\n    /**\n     * Creates a new snapshot of the profiling metrics collected sofar\n     *\n     * @param profiler The {@linkplain Profiler} instance to use\n     * @return Returns an immutable snapshot of the profiling metrics in the form of a map where the\n     *     key is the block name and the value is a map of metrics names and the appropriate values\n     *     <br>\n     *     The supported metrics names are: \"selfTime\", \"wallTime\" and \"invocations\"\n     */\n    public static Profiler.Snapshot snapshot(Profiler profiler) {\n      return BTraceRuntime.snapshot(profiler);\n    }\n\n    public static Profiler.Snapshot snapshotAndReset(Profiler profiler) {\n      return BTraceRuntime.snapshotAndReset(profiler);\n    }\n\n    public static void reset(Profiler profiler) {\n      BTraceRuntime.resetProfiler(profiler);\n    }\n\n    public static void printSnapshot(String name, Profiler profiler) {\n      BTraceRuntime.printSnapshot(name, profiler.snapshot());\n    }\n\n    public static void printSnapshot(String name, Profiler profiler, String format) {\n      BTraceRuntime.printSnapshot(name, profiler.snapshot(), format);\n    }\n  }\n\n  /*\n   * Wraps the speculation related BTrace utility methods\n   * @since 1.2\n   */\n  public static class Speculation {\n    /**\n     * Returns an identifier for a new speculative buffer.\n     *\n     * @return new speculative buffer id\n     */\n    public static int speculation() {\n      return BTraceRuntime.speculation();\n    }\n\n    /**\n     * Sets current speculative buffer id.\n     *\n     * @param id the speculative buffer id\n     */\n    public static void speculate(int id) {\n      BTraceRuntime.speculate(id);\n    }\n\n    /**\n     * Commits the speculative buffer associated with id.\n     *\n     * @param id the speculative buffer id\n     */\n    public static void commit(int id) {\n      BTraceRuntime.commit(id);\n    }\n\n    /**\n     * Discards the speculative buffer associated with id.\n     *\n     * @param id the speculative buffer id\n     */\n    public static void discard(int id) {\n      BTraceRuntime.discard(id);\n    }\n  }\n\n  /*\n   * Wraps the references related BTrace utility methods\n   * @since 1.2\n   */\n  public static class References {\n    /**\n     * Creates and returns a weak reference to the given object.\n     *\n     * @param obj object for which a weak reference is created.\n     * @return a weak reference to the given object.\n     */\n    public static WeakReference weakRef(Object obj) {\n      return new WeakReference<>(obj);\n    }\n\n    /**\n     * Creates and returns a soft reference to the given object.\n     *\n     * @param obj object for which a soft reference is created.\n     * @return a soft reference to the given object.\n     */\n    public static SoftReference softRef(Object obj) {\n      return new SoftReference<>(obj);\n    }\n\n    /**\n     * Returns the given reference object's referent. If the reference object has been cleared,\n     * either by the program or by the garbage collector, then this method returns <code>null</code>\n     * .\n     *\n     * @param ref reference object whose referent is returned.\n     * @return The object to which the reference refers, or <code>null</code> if the reference\n     *     object has been cleared.\n     */\n    public static Object deref(Reference ref) {\n      if (ref.getClass().getClassLoader() == null) {\n        return ref.get();\n      } else {\n        throw new IllegalArgumentException();\n      }\n    }\n  }\n\n  /*\n   * Wraps the reflection related BTrace utility methods\n   * @since 1.2\n   */\n  public static class Reflective {\n    /**\n     * Returns the runtime class of the given Object.\n     *\n     * @param obj the Object whose Class is returned\n     * @return the Class object of given object\n     */\n    public static Class<?> classOf(Object obj) {\n      return obj.getClass();\n    }\n\n    /**\n     * Returns the Class object representing the class or interface that declares the field\n     * represented by the given Field object.\n     *\n     * @param field whose declaring Class is returned\n     */\n    public static Class<?> declaringClass(Field field) {\n      return field.getDeclaringClass();\n    }\n\n    /** Returns the name of the given Class object. */\n    public static String name(Class<?> clazz) {\n      return clazz.getName();\n    }\n\n    /**\n     * Returns the name of the Field object.\n     *\n     * @param field Field for which name is returned\n     * @return name of the given field\n     */\n    public static String name(Field field) {\n      return field.getName();\n    }\n\n    /**\n     * Returns the type of the Field object.\n     *\n     * @param field Field for which type is returned\n     * @return type of the given field\n     */\n    public static Class<?> type(Field field) {\n      return field.getType();\n    }\n\n    /** Returns the access flags of the given Class. */\n    public static int accessFlags(Class<?> clazz) {\n      return clazz.getModifiers();\n    }\n\n    /** Returns the access flags of the given Field. */\n    public static int accessFlags(Field field) {\n      return field.getModifiers();\n    }\n\n    /** Returns the current context class loader */\n    public static ClassLoader contextClassLoader() {\n      return Thread.currentThread().getContextClassLoader();\n    }\n\n    // get Class of the given name\n\n    /** Returns Class object for given class name. */\n    public static Class<?> classForName(String name) {\n      ClassLoader callerLoader = BTraceRuntime.getCallerClassloader(STACK_DEC);\n      return classForName(name, callerLoader);\n    }\n\n    /** Returns the Class for the given class name using the given class loader. */\n    public static Class<?> classForName(String name, ClassLoader cl) {\n      try {\n        return Class.forName(name, false, cl);\n      } catch (ClassNotFoundException exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Determines if the class or interface represented by the first <code>Class</code> object is\n     * either the same as, or is a superclass or superinterface of, the class or interface\n     * represented by the second <code>Class</code> parameter. It returns <code>true</code> if so;\n     * otherwise it returns <code>false</code>.\n     */\n    public static boolean isAssignableFrom(Class<?> a, Class<?> b) {\n      return a.isAssignableFrom(b);\n    }\n\n    /**\n     * Determines if the specified <code>Object</code> is assignment-compatible with the object\n     * represented by the specified <code>Class</code>. This method is the dynamic equivalent of the\n     * Java language <code>instanceof</code> operator. The method returns <code>true</code> if the\n     * specified <code>Object</code> argument is non-null and can be cast to the reference type\n     * represented by this <code>Class</code> object without raising a <code>ClassCastException.\n     * </code> It returns <code>false</code> otherwise.\n     *\n     * @param clazz the class that is checked.\n     * @param obj the object to check.\n     * @return true if <code>obj</code> is an instance of the given class.\n     */\n    public static boolean isInstance(Class<?> clazz, Object obj) {\n      return clazz.isInstance(obj);\n    }\n\n    /**\n     * Returns the <code>Class</code> representing the superclass of the entity (class, interface,\n     * primitive type or void) represented by the given <code>Class</code>. If the given <code>Class\n     * </code> represents either the <code>Object</code> class, an interface, a primitive type, or\n     * void, then null is returned. If the given object represents an array class then the <code>\n     * Class</code> object representing the <code>Object</code> class is returned.\n     *\n     * @param clazz the Class whose super class is returned.\n     * @return the superclass of the class represented by the given object.\n     */\n    public static Class<?> getSuperclass(Class<?> clazz) {\n      return clazz.getSuperclass();\n    }\n\n    /**\n     * Determines if the specified <code>Class</code> object represents an interface type.\n     *\n     * @param clazz the Class object to check.\n     * @return <code>true</code> if the Class represents an interface; <code>false</code> otherwise.\n     */\n    public static boolean isInterface(Class<?> clazz) {\n      return clazz.isInterface();\n    }\n\n    /**\n     * Determines if the given <code>Class</code> object represents an array class.\n     *\n     * @param clazz Class object to check.\n     * @return <code>true</code> if the given object represents an array class; <code>false</code>\n     *     otherwise.\n     */\n    public static boolean isArray(Class<?> clazz) {\n      return clazz.isArray();\n    }\n\n    /** Returns whether the given Class represent primitive type or not. */\n    public static boolean isPrimitive(Class<?> clazz) {\n      return clazz.isPrimitive();\n    }\n\n    /** returns component type of an array Class. */\n    public static Class<?> getComponentType(Class<?> clazz) {\n      return clazz.getComponentType();\n    }\n\n    // Accessing fields by reflection\n\n    /**\n     * Returns a <code>Field</code> object that reflects the specified declared field of the class\n     * or interface represented by the given <code>Class</code> object. The <code>name</code>\n     * parameter is a <code>String</code> that specifies the simple name of the desired field.\n     * Returns <code>null</code> on not finding field if throwException parameter is <code>false\n     * </code>. Else throws a <code>RuntimeException</code> when field is not found.\n     *\n     * @param clazz Class whose field is returned\n     * @param name the name of the field\n     * @param throwException whether to throw exception on failing to find field or not\n     * @return the <code>Field</code> object for the specified field in this class\n     */\n    public static Field field(Class clazz, String name, boolean throwException) {\n      return getField(clazz, name, throwException);\n    }\n\n    /**\n     * Returns a <code>Field</code> object that reflects the specified declared field of the class\n     * or interface represented by the given <code>Class</code> object. The <code>name</code>\n     * parameter is a <code>String</code> that specifies the simple name of the desired field.\n     * Throws a <code>RuntimeException</code> when field is not found.\n     *\n     * @param clazz Class whose field is returned\n     * @param name the name of the field\n     * @return the <code>Field</code> object for the specified field in this class\n     */\n    public static Field field(Class clazz, String name) {\n      return field(clazz, name, true);\n    }\n\n    /**\n     * Returns a <code>Field</code> object that reflects the specified declared field of the class\n     * or interface represented by the given <code>Class</code> object. The <code>name</code>\n     * parameter is a <code>String</code> that specifies the simple name of the desired field.\n     * Returns <code>null</code> on not finding field if throwException parameter is <code>false\n     * </code>. Else throws a <code>RuntimeException</code> when field is not found.\n     *\n     * @param clazz Class whose field is returned\n     * @param name the name of the field\n     * @param throwException whether to throw exception on failing to find field or not\n     * @return the <code>Field</code> object for the specified field in this class\n     */\n    public static Field field(String clazz, String name, boolean throwException) {\n      ClassLoader callerLoader = BTraceRuntime.getCallerClassloader(STACK_DEC);\n      return field(classForName(clazz, callerLoader), name, throwException);\n    }\n\n    /**\n     * Returns a <code>Field</code> object that reflects the specified declared field of the class\n     * or interface represented by the given <code>Class</code> object. The <code>name</code>\n     * parameter is a <code>String</code> that specifies the simple name of the desired field.\n     * Throws a <code>RuntimeException</code> when field is not found.\n     *\n     * @param clazz Class whose field is returned\n     * @param name the name of the field\n     * @return the <code>Field</code> object for the specified field in this class\n     */\n    public static Field field(String clazz, String name) {\n      ClassLoader callerLoader = BTraceRuntime.getCallerClassloader(STACK_DEC);\n      return field(classForName(clazz, callerLoader), name);\n    }\n\n    // field value get methods\n\n    /**\n     * Gets the value of a static <code>byte</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @return the value of the <code>byte</code> field\n     */\n    public static byte getByte(Field field) {\n      checkStatic(field);\n      try {\n        return field.getByte(null);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>byte</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @param obj the object to extract the <code>byte</code> value from\n     * @return the value of the <code>byte</code> field\n     */\n    public static byte getByte(Field field, Object obj) {\n      try {\n        return field.getByte(obj);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>byte</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param instance the object to extract the <code>byte</code> value from\n     * @return the value of the <code>byte</code> field\n     * @since 1.3.5\n     */\n    public static byte getByte(String name, Object instance) {\n      Field f = getField(instance.getClass(), name, true);\n      return getByte(f, instance);\n    }\n\n    /**\n     * Gets the value of a static <code>byte</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param clazz the class to extract the <code>byte</code> value from\n     * @return the value of the <code>byte</code> field\n     * @since 1.3.5\n     */\n    public static byte getByteStatic(String name, Class clazz) {\n      Field f = getField(clazz, name, true);\n      return getByte(f, null);\n    }\n\n    /**\n     * Gets the value of a static <code>short</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @return the value of the <code>short</code> field\n     */\n    public static short getShort(Field field) {\n      checkStatic(field);\n      try {\n        return field.getShort(null);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>short</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @param obj the object to extract the <code>short</code> value from\n     * @return the value of the <code>short</code> field\n     */\n    public static short getShort(Field field, Object obj) {\n      try {\n        return field.getShort(obj);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>short</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param instance the object to extract the <code>short</code> value from\n     * @return the value of the <code>short</code> field\n     * @since 1.3.5\n     */\n    public static short getShort(String name, Object instance) {\n      Field f = getField(instance.getClass(), name, true);\n      return getShort(f, instance);\n    }\n\n    /**\n     * Gets the value of a static <code>short</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param clazz the class to extract the <code>short</code> value from\n     * @return the value of the <code>short</code> field\n     * @since 1.3.5\n     */\n    public static short getShortStatic(String name, Class clazz) {\n      Field f = getField(clazz, name, true);\n      return getShort(f, null);\n    }\n\n    /**\n     * Gets the value of a static <code>int</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @return the value of the <code>int</code> field\n     */\n    public static int getInt(Field field) {\n      checkStatic(field);\n      try {\n        return field.getInt(null);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>int</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @param obj the object to extract the <code>int</code> value from\n     * @return the value of the <code>int</code> field\n     */\n    public static int getInt(Field field, Object obj) {\n      try {\n        return field.getInt(obj);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>int</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param instance the object to extract the <code>int</code> value from\n     * @return the value of the <code>int</code> field\n     * @since 1.3.5\n     */\n    public static int getInt(String name, Object instance) {\n      Field f = getField(instance.getClass(), name, true);\n      return getInt(f, instance);\n    }\n\n    /**\n     * Gets the value of a sttaic <code>int</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param clazz the class to extract the <code>int</code> value from\n     * @return the value of the <code>int</code> field\n     * @since 1.3.5\n     */\n    public static int getIntStatic(String name, Class clazz) {\n      Field f = getField(clazz, name, true);\n      return getInt(f, null);\n    }\n\n    /**\n     * Gets the value of a static <code>long</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @return the value of the <code>long</code> field\n     */\n    public static long getLong(Field field) {\n      checkStatic(field);\n      try {\n        return field.getLong(null);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>long</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @param obj the object to extract the <code>long</code> value from\n     * @return the value of the <code>long</code> field\n     */\n    public static long getLong(Field field, Object obj) {\n      try {\n        return field.getLong(obj);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>long</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param instance the object to extract the <code>long</code> value from\n     * @return the value of the <code>long</code> field\n     * @since 1.3.5\n     */\n    public static long getLong(String name, Object instance) {\n      Field f = getField(instance.getClass(), name, true);\n      return getLong(f, instance);\n    }\n\n    /**\n     * Gets the value of a static <code>long</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param clazz the class to extract the <code>long</code> value from\n     * @return the value of the <code>long</code> field\n     * @since 1.3.5\n     */\n    public static long getLongStatic(String name, Class clazz) {\n      Field f = getField(clazz, name, true);\n      return getLong(f, null);\n    }\n\n    /**\n     * Gets the value of a static <code>float</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @return the value of the <code>float</code> field\n     */\n    public static float getFloat(Field field) {\n      checkStatic(field);\n      try {\n        return field.getFloat(null);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>float</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @param obj the object to extract the <code>float</code> value from\n     * @return the value of the <code>float</code> field\n     */\n    public static float getFloat(Field field, Object obj) {\n      try {\n        return field.getFloat(obj);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>float</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param instance the object to extract the <code>float</code> value from\n     * @return the value of the <code>float</code> field\n     * @since 1.3.5\n     */\n    public static float getFloat(String name, Object instance) {\n      Field f = getField(instance.getClass(), name, true);\n      return getFloat(f, instance);\n    }\n\n    /**\n     * Gets the value of a static <code>float</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param clazz the class to extract the <code>float</code> value from\n     * @return the value of the <code>float</code> field\n     * @since 1.3.5\n     */\n    public static float getFloatStatic(String name, Class clazz) {\n      Field f = getField(clazz, name, true);\n      return getFloat(f, null);\n    }\n\n    /**\n     * Gets the value of a static <code>double</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @return the value of the <code>double</code> field\n     */\n    public static double getDouble(Field field) {\n      checkStatic(field);\n      try {\n        return field.getDouble(null);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>double</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @param instance the object to extract the <code>double</code> value from\n     * @return the value of the <code>double</code> field\n     */\n    public static double getDouble(Field field, Object instance) {\n      try {\n        return field.getDouble(instance);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>double</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param instance the object to extract the <code>double</code> value from\n     * @return the value of the <code>double</code> field\n     * @since 1.3.5\n     */\n    public static double getDouble(String name, Object instance) {\n      Field f = getField(instance.getClass(), name, true);\n      return getDouble(f, instance);\n    }\n\n    /**\n     * Gets the value of a static <code>double</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param clazz the class to extract the <code>double</code> value from\n     * @return the value of the <code>double</code> field\n     * @since 1.3.5\n     */\n    public static double getDouble(String name, Class clazz) {\n      Field f = getField(clazz, name, true);\n      return getDouble(f, null);\n    }\n\n    /**\n     * Gets the value of a static <code>boolean</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @return the value of the <code>boolean</code> field\n     */\n    public static boolean getBoolean(Field field) {\n      checkStatic(field);\n      try {\n        return field.getBoolean(null);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>boolean</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @param obj the object to extract the <code>boolean</code> value from\n     * @return the value of the <code>boolean</code> field\n     */\n    public static boolean getBoolean(Field field, Object obj) {\n      try {\n        return field.getBoolean(obj);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>boolean</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param instance the object to extract the <code>boolean</code> value from\n     * @return the value of the <code>boolean</code> field\n     * @since 1.3.5\n     */\n    public static boolean getBoolean(String name, Object instance) {\n      Field f = getField(instance.getClass(), name, true);\n      return getBoolean(f, instance);\n    }\n\n    /**\n     * Gets the value of a static <code>boolean</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param clazz the class to extract the <code>boolean</code> value from\n     * @return the value of the <code>boolean</code> field\n     * @since 1.3.5\n     */\n    public static boolean getBooleanStatic(String name, Class clazz) {\n      Field f = getField(clazz, name, true);\n      return getBoolean(f, null);\n    }\n\n    /**\n     * Gets the value of a static <code>char</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @return the value of the <code>char</code> field\n     */\n    public static char getChar(Field field) {\n      checkStatic(field);\n      try {\n        return field.getChar(null);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>char</code> field.\n     *\n     * @param field Field object whose value is returned.\n     * @param obj the object to extract the <code>char</code> value from\n     * @return the value of the <code>char</code> field\n     */\n    public static char getChar(Field field, Object obj) {\n      try {\n        return field.getChar(obj);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance <code>char</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param instance the object to extract the <code>char</code> value from\n     * @return the value of the <code>char</code> field\n     * @since 1.3.5\n     */\n    public static char getChar(String name, Object instance) {\n      Field f = getField(instance.getClass(), name, true);\n      return getChar(f, instance);\n    }\n\n    /**\n     * Gets the value of a static <code>char</code> field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param clazz the class to extract the <code>char</code> value from\n     * @return the value of the <code>char</code> field\n     * @since 1.3.5\n     */\n    public static char getCharStatic(String name, Class clazz) {\n      Field f = getField(clazz, name, true);\n      return getChar(f, null);\n    }\n\n    /**\n     * Gets the value of a static reference field.\n     *\n     * @param field Field object whose value is returned.\n     * @return the value of the reference field\n     */\n    public static Object get(Field field) {\n      checkStatic(field);\n      try {\n        return field.get(null);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance reference field.\n     *\n     * @param field Field object whose value is returned.\n     * @param obj the object to extract the reference value from\n     * @return the value of the reference field\n     */\n    public static Object get(Field field, Object obj) {\n      try {\n        return field.get(obj);\n      } catch (Exception exp) {\n        throw translate(exp);\n      }\n    }\n\n    /**\n     * Gets the value of an instance reference field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param instance the object to extract the reference value from\n     * @return the value of the reference field\n     * @since 1.3.5\n     */\n    public static Object get(String name, Object instance) {\n      Field f = getField(instance.getClass(), name, true);\n      return get(f, instance);\n    }\n\n    /**\n     * Gets the value of a static reference field.\n     *\n     * @param name name of the field whose value is returned.\n     * @param clazz the class to extract the reference value from\n     * @return the value of the reference field\n     * @since 1.3.5\n     */\n    public static Object getStatic(String name, Class clazz) {\n      Field f = getField(clazz, name, true);\n      return get(f, null);\n    }\n\n    /**\n     * Print all instance fields of an object as name-value pairs. Includes the inherited fields as\n     * well.\n     *\n     * @param obj Object whose fields are printed.\n     */\n    public static void printFields(Object obj) {\n      printFields(obj, false);\n    }\n\n    /**\n     * Print all instance fields of an object as name-value pairs. Includes the inherited fields as\n     * well. Optionally, prints name of the declaring class before each field - so that if same\n     * named field in super class chain may be disambiguated.\n     *\n     * @param obj Object whose fields are printed.\n     * @param classNamePrefix flag to tell whether to prefix field names names by class name or not.\n     */\n    public static void printFields(Object obj, boolean classNamePrefix) {\n      StringBuilder buf = new StringBuilder();\n      buf.append('{');\n      addFieldValues(buf, obj, obj.getClass(), classNamePrefix);\n      buf.append('}');\n      println(buf.toString());\n    }\n\n    /**\n     * Print all static fields of the class as name-value pairs. Includes the inherited fields as\n     * well.\n     *\n     * @param clazz Class whose static fields are printed.\n     */\n    public static void printStaticFields(Class clazz) {\n      printStaticFields(clazz, false);\n    }\n\n    /**\n     * Print all static fields of the class as name-value pairs. Includes the inherited fields as\n     * well. Optionally, prints name of the declaring class before each field - so that if same\n     * named field in super class chain may be disambigated.\n     *\n     * @param clazz Class whose static fields are printed.\n     * @param classNamePrefix flag to tell whether to prefix field names names by class name or not.\n     */\n    public static void printStaticFields(Class clazz, boolean classNamePrefix) {\n      StringBuilder buf = new StringBuilder();\n      buf.append('{');\n      addStaticFieldValues(buf, clazz, classNamePrefix);\n      buf.append('}');\n      println(buf.toString());\n    }\n  }\n\n  /*\n   * Wraps the data export related BTrace utility methods\n   * @since 1.2\n   */\n  public static class Export {\n    /**\n     * Serialize a given object into the given file. Under the current dir of traced app,\n     * ./btrace&lt;pid&gt;/btrace-class/ directory is created. Under that directory, a file of given\n     * fileName is created.\n     *\n     * @param obj object that has to be serialized.\n     * @param fileName name of the file to which the object is serialized.\n     */\n    public static void serialize(Serializable obj, String fileName) {\n      BTraceRuntime.serialize(obj, fileName);\n    }\n\n    /**\n     * Creates an XML document to persist the tree of the all transitively reachable objects from\n     * given \"root\" object.\n     */\n    public static String toXML(Object obj) {\n      return BTraceRuntime.toXML(obj);\n    }\n\n    /**\n     * Writes an XML document to persist the tree of the all the transitively reachable objects from\n     * the given \"root\" object. Under the current dir of traced app,\n     * ./btrace&lt;pid&gt;/btrace-class/ directory is created. Under that directory, a file of the\n     * given fileName is created.\n     */\n    public static void writeXML(Object obj, String fileName) {\n      BTraceRuntime.writeXML(obj, fileName);\n    }\n\n    /**\n     * Writes a .dot document to persist the tree of the all the transitively reachable objects from\n     * the given \"root\" object. .dot documents can be viewed by Graphviz application\n     * (www.graphviz.org) Under the current dir of traced app, ./btrace&lt;pid&gt;/btrace-class/\n     * directory is created. Under that directory, a file of the given fileName is created.\n     *\n     * @since 1.1\n     */\n    public static void writeDOT(Object obj, String fileName) {\n      BTraceRuntime.writeDOT(obj, fileName);\n    }\n  }\n\n  /*\n   * Wraps the OS related BTrace utility methods\n   * @since 1.2\n   */\n  public static class Sys {\n    /**\n     * Returns n'th command line argument. <code>null</code> if not available.\n     *\n     * @param n command line argument index\n     * @return n'th command line argument\n     */\n    public static String $(int n) {\n      return BTraceRuntime.$(n);\n    }\n\n    /**\n     * Returns a command line argument value for the given key. {@code null} if not available.<br>\n     * In order to provide a key-value pair on the command line it must have the following syntax -\n     * &lt;key&gt;=&lt;value&gt;\n     *\n     * @param key the argument key\n     * @return the corresponding value or {@code null}\n     */\n    public static String $(String key) {\n      return BTraceRuntime.$(key);\n    }\n\n    /** Returns the process id of the currently BTrace'd process. */\n    public static int getpid() {\n      int pid = -1;\n      try {\n        pid = Integer.parseInt($(0));\n      } catch (Exception ignored) {\n      }\n      return pid;\n    }\n\n    /** Returns the number of command line arguments. */\n    public static int $length() {\n      return BTraceRuntime.$length();\n    }\n\n    /**\n     * Exits the BTrace session -- note that the particular client's tracing session exits and not\n     * the observed/traced program! After exit call, the trace action method terminates immediately\n     * and no other probe action method (of that client) will be called after that.\n     *\n     * @param exitCode exit value sent to the client\n     */\n    public static void exit(int exitCode) {\n      BTraceRuntime.exit(exitCode);\n    }\n\n    /**\n     * This is same as exit(int) except that the exit code is zero.\n     *\n     * @see #exit(int)\n     */\n    public static void exit() {\n      exit(0);\n    }\n\n    /*\n     * Wraps the environment related BTrace utility methods\n     * @since 1.2\n     */\n    public static class Env {\n      /**\n       * Gets the system property indicated by the specified key.\n       *\n       * @param key the name of the system property.\n       * @return the string value of the system property, or <code>null</code> if there is no\n       *     property with that key.\n       * @throws NullPointerException if <code>key</code> is <code>null</code>.\n       * @throws IllegalArgumentException if <code>key</code> is empty.\n       */\n      public static String property(String key) {\n        return BTraceRuntime.property(key);\n      }\n\n      /**\n       * Returns all Sys properties.\n       *\n       * @return the system properties\n       */\n      public static Properties properties() {\n        return BTraceRuntime.properties();\n      }\n\n      /** Prints all Sys properties. */\n      public static void printProperties() {\n        BTraceRuntime.printMap(properties());\n      }\n\n      /**\n       * Gets the value of the specified environment variable. An environment variable is a\n       * system-dependent external named value.\n       *\n       * @param name the name of the environment variable\n       * @return the string value of the variable, or <code>null</code> if the variable is not\n       *     defined in the system environment\n       * @throws NullPointerException if <code>name</code> is <code>null</code>\n       */\n      public static String getenv(String name) {\n        return BTraceRuntime.getenv(name);\n      }\n\n      /**\n       * Returns an unmodifiable string map view of the current system environment. The environment\n       * is a system-dependent mapping from names to values which is passed from parent to child\n       * processes.\n       *\n       * @return the environment as a map of variable names to values\n       */\n      public static Map<String, String> getenv() {\n        return BTraceRuntime.getenv();\n      }\n\n      /** Prints all system environment values. */\n      public static void printEnv() {\n        BTraceRuntime.printMap(getenv());\n      }\n\n      /**\n       * Returns the number of processors available to the Java virtual machine.\n       *\n       * <p>This value may change during a particular invocation of the virtual machine.\n       * Applications that are sensitive to the number of available processors should therefore\n       * occasionally poll this property and adjust their resource usage appropriately.\n       *\n       * @return the maximum number of processors available to the virtual machine; never smaller\n       *     than one\n       */\n      public static long availableProcessors() {\n        return Runtime.getRuntime().availableProcessors();\n      }\n    }\n\n    /*\n     * Wraps the memory related BTrace utility methods\n     * @since 1.2\n     */\n    public static class Memory {\n      // memory usage\n\n      /**\n       * Returns the amount of free memory in the Java Virtual Machine. Calling the <code>gc</code>\n       * method may result in increasing the value returned by <code>freeMemory.</code>\n       *\n       * @return an approximation to the total amount of memory currently available for future\n       *     allocated objects, measured in bytes.\n       */\n      public static long freeMemory() {\n        return Runtime.getRuntime().freeMemory();\n      }\n\n      /**\n       * Returns the total amount of memory in the Java virtual machine. The value returned by this\n       * method may vary over time, depending on the host environment.\n       *\n       * <p>Note that the amount of memory required to hold an object of any given type may be\n       * implementation-dependent.\n       *\n       * @return the total amount of memory currently available for current and future objects,\n       *     measured in bytes.\n       */\n      public static long totalMemory() {\n        return Runtime.getRuntime().totalMemory();\n      }\n\n      /**\n       * Returns the maximum amount of memory that the Java virtual machine will attempt to use. If\n       * there is no inherent limit then the value {@link java.lang.Long#MAX_VALUE} will be\n       * returned.\n       *\n       * @return the maximum amount of memory that the virtual machine will attempt to use, measured\n       *     in bytes\n       */\n      public static long maxMemory() {\n        return Runtime.getRuntime().maxMemory();\n      }\n\n      /** Returns heap memory usage */\n      public static MemoryUsage heapUsage() {\n        return BTraceRuntime.heapUsage();\n      }\n\n      /** Returns non-heap memory usage */\n      public static MemoryUsage nonHeapUsage() {\n        return BTraceRuntime.nonHeapUsage();\n      }\n\n      /**\n       * Returns the amount of memory in bytes that the Java virtual machine initially requests from\n       * the operating system for memory management.\n       */\n      public static long init(MemoryUsage mu) {\n        return mu.getInit();\n      }\n\n      /**\n       * Returns the amount of memory in bytes that is committed for the Java virtual machine to\n       * use. This amount of memory is guaranteed for the Java virtual machine to use.\n       */\n      public static long committed(MemoryUsage mu) {\n        return mu.getCommitted();\n      }\n\n      /**\n       * Returns the maximum amount of memory in bytes that can be used for memory management. This\n       * method returns -1 if the maximum memory size is undefined.\n       */\n      public static long max(MemoryUsage mu) {\n        return mu.getMax();\n      }\n\n      /** Returns the amount of used memory in bytes. */\n      public static long used(MemoryUsage mu) {\n        return mu.getUsed();\n      }\n\n      /** Returns the approximate number of objects for which finalization is pending. */\n      public static long finalizationCount() {\n        return BTraceRuntime.finalizationCount();\n      }\n\n      /**\n       * Dump the snapshot of the Java heap to a file in hprof binary format. Only the live objects\n       * are dumped. Under the current dir of traced app, ./btrace&lt;pid&gt;/btrace-class/\n       * directory is created. Under that directory, a file of given fileName is created.\n       *\n       * @param fileName name of the file to which heap is dumped\n       */\n      public static void dumpHeap(String fileName) {\n        dumpHeap(fileName, true);\n      }\n\n      /**\n       * Dump the snapshot of the Java heap to a file in hprof binary format. Under the current dir\n       * of traced app, ./btrace&lt;pid&gt;/btrace-class/ directory is created. Under that\n       * directory, a file of given fileName is created.\n       *\n       * @param fileName name of the file to which heap is dumped\n       * @param live flag that tells whether only live objects are to be dumped or all objects are\n       *     to be dumped.\n       */\n      public static void dumpHeap(String fileName, boolean live) {\n        BTraceRuntime.dumpHeap(fileName, live);\n      }\n\n      /**\n       * Runs the garbage collector.\n       *\n       * <p>Calling the <code>gc</code> method suggests that the Java Virtual Machine expend effort\n       * toward recycling unused objects in order to make the memory they currently occupy available\n       * for quick reuse. When control returns from the method call, the Java Virtual Machine has\n       * made a best effort to reclaim space from all discarded objects. This method calls Sys.gc()\n       * to perform GC.\n       */\n      public static void gc() {\n        java.lang.System.gc();\n      }\n\n      /**\n       * Returns the total amount of time spent in GarbageCollection up to this point since the\n       * application was started.\n       *\n       * @return Returns the amount of overall time spent in GC\n       */\n      public static long getTotalGcTime() {\n        return BTraceRuntime.getTotalGcTime();\n      }\n\n      /**\n       * Returns an overview of available memory pools <br>\n       * It is possible to provide a text format the overview will use\n       *\n       * @param poolFormat The text format string to format the overview. <br>\n       *     Exactly 5 arguments are passed to the format function. <br>\n       *     The format defaults to \";%1$s;%2$d;%3$d;%4$d;%5$d;Memory]\"\n       * @return Returns the formatted value of memory pools overview\n       * @since 1.2\n       */\n      public static String getMemoryPoolUsage(String poolFormat) {\n        return BTraceRuntime.getMemoryPoolUsage(poolFormat);\n      }\n\n      /**\n       * Runs the finalization methods of any objects pending finalization.\n       *\n       * <p>Calling this method suggests that the Java Virtual Machine expend effort toward running\n       * the <code>finalize</code> methods of objects that have been found to be discarded but whose\n       * <code>finalize</code> methods have not yet been run. When control returns from the method\n       * call, the Java Virtual Machine has made a best effort to complete all outstanding\n       * finalizations. This method calls Sys.runFinalization() to run finalization.\n       */\n      public static void runFinalization() {\n        java.lang.System.runFinalization();\n      }\n    }\n\n    /*\n     * Wraps the VM related BTrace utility methods\n     * @since 1.2\n     */\n    public static class VM {\n      /**\n       * Returns the input arguments passed to the Java virtual machine which does not include the\n       * arguments to the <tt>main</tt> method. This method returns an empty list if there is no\n       * input argument to the Java virtual machine.\n       *\n       * <p>Some Java virtual machine implementations may take input arguments from multiple\n       * different sources: for examples, arguments passed from the application that launches the\n       * Java virtual machine such as the 'java' command, environment variables, configuration\n       * files, etc.\n       *\n       * <p>Typically, not all command-line options to the 'java' command are passed to the Java\n       * virtual machine. Thus, the returned input arguments may not include all command-line\n       * options.\n       *\n       * @return a list of <tt>String</tt> objects; each element is an argument passed to the Java\n       *     virtual machine.\n       */\n      public static List<String> vmArguments() {\n        return BTraceRuntime.getInputArguments();\n      }\n\n      /**\n       * Prints VM input arguments list.\n       *\n       * @see #vmArguments\n       */\n      public static void printVmArguments() {\n        println(vmArguments());\n      }\n\n      /**\n       * Returns the Java virtual machine implementation version. This method is equivalent to\n       * <b>Sys.getProperty(\"java.vm.version\")}</b>.\n       *\n       * @return the Java virtual machine implementation version.\n       */\n      public static String vmVersion() {\n        return BTraceRuntime.getVmVersion();\n      }\n\n      /**\n       * Tests if the Java virtual machine supports the boot class path mechanism used by the\n       * bootstrap class loader to search for class files.\n       *\n       * @return <tt>true</tt> if the Java virtual machine supports the class path mechanism;\n       *     <tt>false</tt> otherwise.\n       */\n      public static boolean isBootClassPathSupported() {\n        return BTraceRuntime.isBootClassPathSupported();\n      }\n\n      /**\n       * Returns the boot class path that is used by the bootstrap class loader to search for class\n       * files.\n       *\n       * <p>Multiple paths in the boot class path are separated by the path separator character of\n       * the platform on which the Java virtual machine is running.\n       *\n       * <p>A Java virtual machine implementation may not support the boot class path mechanism for\n       * the bootstrap class loader to search for class files. The {@link #isBootClassPathSupported}\n       * method can be used to determine if the Java virtual machine supports this method.\n       *\n       * @return the boot class path.\n       * @throws java.lang.UnsupportedOperationException if the Java virtual machine does not\n       *     support this operation.\n       */\n      public static String bootClassPath() {\n        return BTraceRuntime.getBootClassPath();\n      }\n\n      /**\n       * Returns the Java class path that is used by the system class loader to search for class\n       * files. This method is equivalent to <b>Sys.getProperty(\"java.class.path\")</b>.\n       *\n       * @return the Java class path.\n       */\n      public static String classPath() {\n        return Sys.Env.property(\"java.class.path\");\n      }\n\n      /**\n       * Returns the Java library path. This method is equivalent to\n       * <b>Sys.getProperty(\"java.library.path\")</b>.\n       *\n       * <p>Multiple paths in the Java library path are separated by the path separator character of\n       * the platform of the Java virtual machine being monitored.\n       *\n       * @return the Java library path.\n       */\n      public static String libraryPath() {\n        return Sys.Env.property(\"java.library.path\");\n      }\n\n      /**\n       * Returns the current number of live threads including both daemon and non-daemon threads.\n       *\n       * @return the current number of live threads.\n       */\n      public static long threadCount() {\n        return BTraceRuntime.getThreadCount();\n      }\n\n      /**\n       * Returns the peak live thread count since the Java virtual machine started or peak was\n       * reset.\n       *\n       * @return the peak live thread count.\n       */\n      public static long peakThreadCount() {\n        return BTraceRuntime.getPeakThreadCount();\n      }\n\n      /**\n       * Returns the total number of threads created and also started since the Java virtual machine\n       * started.\n       *\n       * @return the total number of threads started.\n       */\n      public static long totalStartedThreadCount() {\n        return BTraceRuntime.getTotalStartedThreadCount();\n      }\n\n      /**\n       * Returns the current number of live daemon threads.\n       *\n       * @return the current number of live daemon threads.\n       */\n      public static long daemonThreadCount() {\n        return BTraceRuntime.getDaemonThreadCount();\n      }\n\n      /**\n       * Returns the system load average for the last minute\n       *\n       * @return the system load average for the last minute\n       */\n      public static double systemLoadAverage() {\n        return BTraceRuntime.getSystemLoadAverage();\n      }\n\n      /**\n       * Returns the CPU time used by the process on which the Java virtual machine is running in\n       * nanoseconds.\n       *\n       * @return the CPU time used by the process on which the JVM is running in nanoseconds.\n       *     Returns -1 if this operation is not supported on this platform\n       */\n      public static long processCPUTime() {\n        return BTraceRuntime.getProcessCPUTime();\n      }\n\n      /**\n       * Returns the start time of the Java virtual machine in milliseconds. This method returns the\n       * approximate time when the Java virtual machine started.\n       *\n       * @return start time of the Java virtual machine in milliseconds.\n       */\n      public static long vmStartTime() {\n        return BTraceRuntime.vmStartTime();\n      }\n\n      /**\n       * Returns the uptime of the Java virtual machine in milliseconds.\n       *\n       * @return uptime of the Java virtual machine in milliseconds.\n       */\n      public static long vmUptime() {\n        return BTraceRuntime.vmUptime();\n      }\n\n      /**\n       * Returns the total CPU time for the current thread in nanoseconds. The returned value is of\n       * nanoseconds precision but not necessarily nanoseconds accuracy. If the implementation\n       * distinguishes between user mode time and system mode time, the returned CPU time is the\n       * amount of time that the current thread has executed in user mode or system mode.\n       */\n      public static long currentThreadCpuTime() {\n        return BTraceRuntime.getCurrentThreadCpuTime();\n      }\n\n      /**\n       * Returns the CPU time that the current thread has executed in user mode in nanoseconds. The\n       * returned value is of nanoseconds precision but not necessarily nanoseconds accuracy.\n       */\n      public static long currentThreadUserTime() {\n        return BTraceRuntime.getCurrentThreadUserTime();\n      }\n    }\n  }\n\n  /*\n   * Wraps the jvmstat counters related BTrace utility methods\n   * @since 1.2\n   */\n  public static class Counters {\n    /** accessing jvmstat (perf) int counter */\n    public static long perfInt(String name) {\n      return BTraceRuntime.perfInt(name);\n    }\n\n    /** accessing jvmstat (perf) long counter */\n    public static long perfLong(String name) {\n      return BTraceRuntime.perfLong(name);\n    }\n\n    /** accessing jvmstat (perf) String counter */\n    public static String perfString(String name) {\n      return BTraceRuntime.perfString(name);\n    }\n  }\n\n  /*\n   * Wraps the dtrace related BTrace utility methods\n   * @since 1.2\n   */\n  public static class D {\n    /**\n     * BTrace to DTrace communication chennal. Raise DTrace USDT probe from BTrace.\n     *\n     * @see #dtraceProbe(String, String, int, int)\n     */\n    public static int probe(String str1, String str2) {\n      return probe(str1, str2, -1, -1);\n    }\n\n    /**\n     * BTrace to DTrace communication chennal. Raise DTrace USDT probe from BTrace.\n     *\n     * @see #dtraceProbe(String, String, int, int)\n     */\n    public static int probe(String str1, String str2, int i1) {\n      return probe(str1, str2, i1, -1);\n    }\n\n    /**\n     * BTrace to DTrace communication channel. Raise DTrace USDT probe from BTrace.\n     *\n     * @param str1 first String param to DTrace probe\n     * @param str2 second String param to DTrace probe\n     * @param i1 first int param to DTrace probe\n     * @param i2 second int param to DTrace probe\n     */\n    public static int probe(String str1, String str2, int i1, int i2) {\n      return BTraceRuntime.dtraceProbe(str1, str2, i1, i2);\n    }\n  }\n\n  /**\n   * Support for JFR integration.\n   *\n   * @since 2.1.0\n   */\n  public static final class Jfr {\n    /**\n     * Create a new event instance using the factory field annotated by {@linkplain\n     * org.openjdk.btrace.core.annotations.Event}\n     *\n     * @param eventFactory the event factory\n     * @return new event instance\n     */\n    public static JfrEvent prepareEvent(JfrEvent.Factory eventFactory) {\n      return eventFactory.newEvent();\n    }\n\n    /**\n     * Set an event field value\n     *\n     * @param event event instance\n     * @param fieldName field name\n     * @param fieldValue field value\n     */\n    public static void setEventField(JfrEvent event, String fieldName, byte fieldValue) {\n      event.withValue(fieldName, fieldValue);\n    }\n\n    /**\n     * Set an event field value\n     *\n     * @param event event instance\n     * @param fieldName field name\n     * @param fieldValue field value\n     */\n    public static void setEventField(JfrEvent event, String fieldName, char fieldValue) {\n      event.withValue(fieldName, fieldValue);\n    }\n\n    /**\n     * Set an event field value\n     *\n     * @param event event instance\n     * @param fieldName field name\n     * @param fieldValue field value\n     */\n    public static void setEventField(JfrEvent event, String fieldName, short fieldValue) {\n      event.withValue(fieldName, fieldValue);\n    }\n\n    /**\n     * Set an event field value\n     *\n     * @param event event instance\n     * @param fieldName field name\n     * @param fieldValue field value\n     */\n    public static void setEventField(JfrEvent event, String fieldName, int fieldValue) {\n      event.withValue(fieldName, fieldValue);\n    }\n\n    /**\n     * Set an event field value\n     *\n     * @param event event instance\n     * @param fieldName field name\n     * @param fieldValue field value\n     */\n    public static void setEventField(JfrEvent event, String fieldName, long fieldValue) {\n      event.withValue(fieldName, fieldValue);\n    }\n\n    /**\n     * Set an event field value\n     *\n     * @param event event instance\n     * @param fieldName field name\n     * @param fieldValue field value\n     */\n    public static void setEventField(JfrEvent event, String fieldName, float fieldValue) {\n      event.withValue(fieldName, fieldValue);\n    }\n\n    /**\n     * Set an event field value\n     *\n     * @param event event instance\n     * @param fieldName field name\n     * @param fieldValue field value\n     */\n    public static void setEventField(JfrEvent event, String fieldName, double fieldValue) {\n      event.withValue(fieldName, fieldValue);\n    }\n\n    /**\n     * Set an event field value\n     *\n     * @param event event instance\n     * @param fieldName field name\n     * @param fieldValue field value\n     */\n    public static void setEventField(JfrEvent event, String fieldName, boolean fieldValue) {\n      event.withValue(fieldName, fieldValue);\n    }\n\n    /**\n     * Set an event field value\n     *\n     * @param event event instance\n     * @param fieldName field name\n     * @param fieldValue field value\n     */\n    public static void setEventField(JfrEvent event, String fieldName, String fieldValue) {\n      event.withValue(fieldName, fieldValue);\n    }\n\n    /**\n     * Check whether the event should be committed.\n     *\n     * @see Event#shouldCommit()\n     * @param event event to check\n     * @return {@literal true} if the event should be committed\n     */\n    public static boolean shouldCommit(JfrEvent event) {\n      return event.shouldCommit();\n    }\n\n    /**\n     * Commit the event\n     *\n     * @see Event#commit()\n     * @param event the event to commit\n     */\n    public static void commit(JfrEvent event) {\n      event.commit();\n    }\n\n    public static void begin(JfrEvent event) {\n      event.begin();\n    }\n\n    public static void end(JfrEvent event) {\n      event.end();\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/CircularBuffer.java",
    "content": "package org.openjdk.btrace.core;\n\npublic final class CircularBuffer<T> {\n  private final T[] elements;\n  private final int size;\n  private long readIndex = 0;\n  private long writeIndex = -1;\n  private int length = 0;\n\n  @SuppressWarnings(\"unchecked\")\n  public CircularBuffer(int size) {\n    this.size = size;\n    elements = (T[]) new Object[size];\n  }\n\n  public void add(T element) {\n    int newIndex = (int) (++writeIndex) % size;\n    elements[newIndex] = element;\n    int nextIndex = (newIndex + 1) % size;\n    if (elements[nextIndex] != null) {\n      readIndex = nextIndex;\n    }\n    if (++length > size) {\n      length = size;\n    }\n  }\n\n  public boolean forEach(Function<T, Boolean> functor) {\n    int cntr = 0;\n    while (cntr < size && writeIndex >= readIndex) {\n      if (functor.apply(elements[(int) readIndex % size])) {\n        readIndex++;\n        if (--length < 0) {\n          length = 0;\n        }\n      } else {\n        return false;\n      }\n      cntr++;\n    }\n    return true;\n  }\n\n  public boolean doNext(Function<T, Boolean> nextWork) {\n    if (writeIndex >= readIndex) {\n      if (nextWork.apply(elements[(int) readIndex % size])) {\n        readIndex++;\n        return true;\n      }\n    }\n    return false;\n  }\n\n  public int getLength() {\n    return length;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/DebugSupport.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.core;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\nimport org.slf4j.Logger;\nimport org.slf4j.impl.SimpleLogger;\n\n/**\n * Centralized support for logging various debug information.\n *\n * @author Jaroslav Bachorik\n */\npublic final class DebugSupport {\n  public static void initLoggers(boolean debug, Logger logger) {\n    String logFile = System.getProperty(\"org.slf4j.simpleLogger.logFile\");\n    System.setProperty(\"org.slf4j.simpleLogger.logFile\", logFile != null ? logFile : \"System.out\");\n    String defaultLevel =\n        System.getProperty(\"org.slf4j.simpleLogger.log.org.openjdk.btrace\", \"info\");\n    System.setProperty(\"org.slf4j.simpleLogger.defaultLogLevel\", debug ? \"debug\" : defaultLevel);\n    try {\n      Method mthd = SimpleLogger.class.getDeclaredMethod(\"init\");\n      mthd.setAccessible(true);\n      mthd.invoke(null);\n    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {\n      System.err.println(\"[btrace] Unable to reload logger config\");\n    }\n    if (logger != null) {\n      try {\n        Field fld = logger.getClass().getDeclaredField(\"currentLogLevel\");\n        fld.setAccessible(true);\n        fld.set(\n            logger,\n            debug\n                ? 10\n                : 20); // 10 is the 'debug' level for SLF4J SimpleLogger, 20 is the info level\n      } catch (NoSuchFieldException | IllegalAccessException e) {\n        System.err.println(\"[btrace] Unable to set debug log level\");\n        e.printStackTrace(System.err);\n      }\n    }\n  }\n\n  private final SharedSettings settings;\n\n  public DebugSupport(SharedSettings s) {\n    settings = s != null ? s : SharedSettings.GLOBAL;\n  }\n\n  public boolean isDebug() {\n    return settings.isDebug();\n  }\n\n  public boolean isDumpClasses() {\n    return settings.isDumpClasses();\n  }\n\n  public String getDumpClassDir() {\n    return settings.getDumpDir();\n  }\n\n  public void dumpClass(String className, byte[] code) {\n    if (settings.isDumpClasses()) {\n      try {\n        className = className.replace(\".\", File.separator).replace(\"/\", File.separator);\n        int index = className.lastIndexOf(File.separatorChar);\n        StringBuilder buf = new StringBuilder();\n        if (!settings.getDumpDir().equals(\".\")) {\n          buf.append(settings.getDumpDir());\n          buf.append(File.separatorChar);\n        }\n        String dir = buf.toString();\n        if (index != -1) {\n          dir += className.substring(0, index);\n        }\n        new File(dir).mkdirs();\n        String file;\n        if (index != -1) {\n          file = className.substring(index + 1);\n        } else {\n          file = className;\n        }\n        file += \".class\";\n        new File(dir).mkdirs();\n        File out = new File(dir, file);\n        try (FileOutputStream fos = new FileOutputStream(out)) {\n          fos.write(code);\n        }\n      } catch (Exception exp) {\n        exp.printStackTrace();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/Function.java",
    "content": "package org.openjdk.btrace.core;\n\npublic interface Function<T, R> {\n  R apply(T value);\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/HandlerRepository.java",
    "content": "package org.openjdk.btrace.core;\n\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodType;\n\n/**\n * A bridge interface between a handler repository implementation and the invoke dynamic bootstrap\n * class doing the handler lookup.\n */\n@FunctionalInterface\npublic interface HandlerRepository {\n  MethodHandle resolveHandler(String probeName, String handlerName, MethodType handlerType);\n}"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/Messages.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core;\n\nimport java.text.MessageFormat;\nimport java.util.Locale;\nimport java.util.ResourceBundle;\n\npublic final class Messages {\n  private static final ResourceBundle messages;\n\n  static {\n    messages =\n        ResourceBundle.getBundle(\n            \"org.openjdk.btrace.core.messages\",\n            Locale.getDefault(),\n            Messages.class.getClassLoader());\n  }\n\n  private Messages() {}\n\n  public static String get(String key) {\n    return messages.getString(key);\n  }\n\n  public static String format(String key, Object... args) {\n    return MessageFormat.format(get(key), args);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/MethodID.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * A factory class for shared method ids\n *\n * @author Jaroslav Bachorik\n */\npublic class MethodID {\n  static final AtomicInteger lastMethodId = new AtomicInteger(1);\n  // Use a concurrent map to ensure thread-safe access without external synchronization\n  private static final ConcurrentHashMap<String, Integer> methodIds = new ConcurrentHashMap<>();\n\n  /**\n   * Generates a unique method id based on the provided method tag\n   *\n   * @param methodTag The tag used to distinguish between methods\n   * @return An ID belonging to the provided method tag\n   */\n  public static int getMethodId(String methodTag) {\n    return methodIds.computeIfAbsent(methodTag, k -> lastMethodId.getAndIncrement());\n  }\n\n  public static int getMethodId(String className, String method, String desc) {\n    return getMethodId(className + \"#\" + method + \"#\" + desc);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/PrefixMap.java",
    "content": "/*\n * Copyright (c) 2017, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\npackage org.openjdk.btrace.core;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/** Simplified trie-based prefix map */\npublic class PrefixMap {\n  private final Node root = new Node();\n\n  public void add(CharSequence val) {\n    Node n = root;\n    for (int i = 0; i < val.length(); i++) {\n      char ch = val.charAt(i);\n      Node child = n.getReferencedNode(ch);\n      if (child == null) {\n        child = new Node();\n        n.addReferencedNode(ch, child);\n      }\n      n = child;\n    }\n    n.setValue(val);\n  }\n\n  public boolean contains(CharSequence val) {\n    Node n = root;\n    for (int i = 0; i < val.length(); i++) {\n      char ch = val.charAt(i);\n      Node child = n.getReferencedNode(ch);\n      if (child == null) {\n        return false;\n      }\n      if (child.value != null) {\n        return true;\n      }\n      n = child;\n    }\n    return false;\n  }\n\n  private static final class Node {\n    private final Map<Character, Node> refs = new HashMap<>();\n    private CharSequence value;\n\n    public Node() {\n      value = null;\n    }\n\n    public Node getReferencedNode(char ch) {\n      return refs.get(ch);\n    }\n\n    public void addReferencedNode(char ch, Node n) {\n      refs.putIfAbsent(ch, n);\n    }\n\n    public void setValue(CharSequence val) {\n      value = val;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/Profiler.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Objects;\nimport org.openjdk.btrace.core.annotations.Property;\n\n/**\n * Profiler is a highly specialized aggregation-like data collector optimized for high-speed\n * collection of the application execution call tree data. <br>\n * <br>\n * <cite>It is exposable as MBean via {@linkplain Property} annotation</cite>\n *\n * @author Jaroslav Bachorik\n * @since 1.2\n */\npublic abstract class Profiler {\n  /**\n   * This property exposes the time of creating this particular {@linkplain Profiler} instance. <br>\n   * The unit is milliseconds.\n   */\n  public final long START_TIME;\n\n  /** Creates a new {@linkplain Profiler} instance */\n  public Profiler() {\n    START_TIME = System.currentTimeMillis();\n  }\n\n  /**\n   * Records the event of entering an execution unit (eg. method)<br>\n   * Must be paired with a call to {@linkplain Profiler#recordExit(java.lang.String, long) } with\n   * the same blockName, eventually\n   *\n   * @param blockName The execution unit identifier (eg. method FQN)\n   */\n  public abstract void recordEntry(String blockName);\n\n  /**\n   * Records the event of exiting an execution unit (eg. method)<br>\n   * Must be preceded by a call to {@linkplain Profiler#recordEntry(java.lang.String) } with the\n   * same blockName\n   *\n   * @param blockName The execution unit identifier (eg. method FQN)\n   * @param duration Invocation duration in nanoseconds\n   */\n  public abstract void recordExit(String blockName, long duration);\n\n  /**\n   * Creates an immutable snapshot of the collected profiling data\n   *\n   * @return Returns the immutable {@linkplain Snapshot} instance\n   */\n  public final Snapshot snapshot() {\n    return snapshot(false);\n  }\n\n  /**\n   * Creates an immutable snapshot of the collected profiling data.<br>\n   * Makes it possible to reset the profiler after creating the snapshot, eventually\n   *\n   * @param reset Signals the profiler to perform reset right after getting the snapshot (in an\n   *     atomic transaction)\n   * @return Returns the immutable {@linkplain Snapshot} instance\n   */\n  public abstract Snapshot snapshot(boolean reset);\n\n  /** Resets all the collected data */\n  public abstract void reset();\n\n  /** Helper interface to make accessing a {@linkplain Profiler} as an MBean type safe. */\n  public interface MBeanValueProvider {\n    Snapshot getMBeanValue();\n  }\n\n  /**\n   * Record represents an atomic unit in the application execution call tree\n   *\n   * @since 1.2\n   */\n  public static final class Record {\n    public static final Comparator<Record> COMPARATOR =\n        (o1, o2) -> {\n          if (o1 == null && o2 != null) return 1;\n          if (o1 != null && o2 == null) return -1;\n          if (o1 == null && o2 == null) return 0;\n          return o1.blockName.compareTo(o2.blockName);\n        };\n\n    public final String blockName;\n    public long wallTime = 0, wallTimeMax = 0, wallTimeMin = Long.MAX_VALUE;\n    public long selfTime = 0, selfTimeMax = 0, selfTimeMin = Long.MAX_VALUE;\n    public long invocations = 1;\n    public boolean onStack = false;\n    public Record referring = null;\n\n    public Record(String blockName) {\n      this.blockName = blockName;\n    }\n\n    public Record duplicate() {\n      Record r = new Record(blockName);\n      r.invocations = invocations;\n      r.selfTime = selfTime;\n      r.selfTimeMax = selfTimeMax;\n      r.selfTimeMin = selfTimeMin;\n      r.wallTime = wallTime;\n      r.wallTimeMax = wallTimeMax;\n      r.wallTimeMin = wallTimeMin;\n      return r;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n      if (obj == null) {\n        return false;\n      }\n      if (getClass() != obj.getClass()) {\n        return false;\n      }\n      Record other = (Record) obj;\n      if (!Objects.equals(blockName, other.blockName)) {\n        return false;\n      }\n      if (wallTime != other.wallTime) {\n        return false;\n      }\n      if (selfTime != other.selfTime) {\n        return false;\n      }\n      return invocations == other.invocations;\n    }\n\n    @Override\n    public int hashCode() {\n      int hash = 7;\n      hash = 17 * hash + (blockName != null ? blockName.hashCode() : 0);\n      hash = 17 * hash + (int) (wallTime ^ (wallTime >>> 32));\n      hash = 17 * hash + (int) (selfTime ^ (selfTime >>> 32));\n      hash = 17 * hash + (int) (invocations ^ (invocations >>> 32));\n      return hash;\n    }\n\n    @Override\n    public String toString() {\n      return \"Record{\\n\"\n          + \"\\tblockName=\"\n          + blockName\n          + \"\\n,\"\n          + \"\\twallTime=\"\n          + wallTime\n          + \",\\n\"\n          + \"\\twallTime.min=\"\n          + wallTimeMin\n          + \",\\n\"\n          + \"\\twallTime.max=\"\n          + wallTimeMax\n          + \",\\n\"\n          + \"\\tselfTime=\"\n          + selfTime\n          + \",\\n\"\n          + \"\\tselfTime.min=\"\n          + selfTimeMin\n          + \",\\n\"\n          + \"\\tselfTime.max=\"\n          + selfTimeMax\n          + \",\\n\"\n          + \"\\tinvocations=\"\n          + invocations\n          + \",\\nonStack=\"\n          + onStack\n          + '}';\n    }\n  }\n\n  /**\n   * Snapshot is an immutable image of the current profiling data collected by the {@linkplain\n   * Profiler} <br>\n   * <br>\n   * It is created by calling {@linkplain Profiler#snapshot()} method\n   *\n   * @since 1.2\n   */\n  public static final class Snapshot {\n    public final long timeStamp;\n    public final long timeInterval;\n    public final Record[] total;\n\n    public Snapshot(Record[] data, long startTs, long stopTs) {\n      timeStamp = stopTs;\n      timeInterval = stopTs - startTs;\n      total = data;\n    }\n\n    public List<Object[]> getGridData() {\n      List<Object[]> rslt = new ArrayList<>();\n\n      Object[] titleRow = {\n        \"Block\",\n        \"Invocations\",\n        \"SelfTime.Total\",\n        \"SelfTime.Avg\",\n        \"SelfTime.Min\",\n        \"SelfTime.Max\",\n        \"WallTime.Total\",\n        \"WallTime.Avg\",\n        \"WallTime.Min\",\n        \"WallTime.Max\"\n      };\n\n      rslt.add(titleRow);\n\n      for (Record r : total) {\n        if (r != null) {\n          Object[] row = {\n            r.blockName,\n            r.invocations,\n            r.selfTime,\n            r.selfTime / r.invocations,\n            r.selfTimeMin < Long.MAX_VALUE ? r.selfTimeMin : \"N/A\",\n            r.selfTimeMax > 0 ? r.selfTimeMax : \"N/A\",\n            r.wallTime,\n            r.wallTime / r.invocations,\n            r.wallTimeMin < Long.MAX_VALUE ? r.wallTimeMin : \"N/A\",\n            r.wallTimeMax > 0 ? r.wallTimeMax : \"N/A\"\n          };\n          rslt.add(row);\n        }\n      }\n      return rslt;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/SharedSettings.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.core;\n\nimport java.util.Map;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.core.extensions.PermissionSet;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic final class SharedSettings {\n  public static final String DEBUG_KEY = \"debug\";\n  public static final String DUMP_DIR_KEY = \"dumpDir\";\n  @Deprecated public static final String UNSAFE_KEY = \"unsafe\";\n  public static final String TRUSTED_KEY = \"trusted\";\n  public static final String TRACK_RETRANSFORMS_KEY = \"trackRetransforms\";\n  public static final String PROBE_DESC_PATH_KEY = \"probeDescPath\";\n  public static final String STATSD_HOST_KEY = \"statsdHost\";\n  public static final String STATSD_PORT_KEY = \"statsdPort\";\n  public static final String FILEROLL_INTERVAL_KEY = \"fileRollMilliseconds\";\n  public static final String FILEROLL_MAXROLLS_KEY = \"fileRollMaxRolls\";\n  public static final String OUTPUT_FILE_KEY = \"scriptOutputFile\";\n  public static final String OUTPUT_DIR_KEY = \"scriptOutputDir\";\n  public static final String GRANT_PERMISSIONS_KEY = \"grantPermissions\";\n  public static final String DENY_PERMISSIONS_KEY = \"denyPermissions\";\n  public static final String GRANT_ALL_KEY = \"grantAll\";\n\n  public static final SharedSettings GLOBAL = new SharedSettings();\n\n  private boolean debug = false;\n  private boolean trusted = false;\n  private boolean trackRetransforms = false;\n  private boolean retransformStartup = true;\n  private String dumpDir = null;\n  private String probeDescPath = \".\";\n  private String bootClassPath = \"\";\n  private final String systemClassPath = \"\";\n  private String statsdHost = null;\n  private int statsdPort = 8125; // default statsd port\n  private int fileRollMilliseconds = Integer.MIN_VALUE;\n  private int fileRollMaxRolls = 5; // default hold max 100 logs\n  private String outputFile;\n  private String scriptDir;\n  private String scriptOutputDir;\n  private String clientName;\n  private PermissionSet grantedPermissions = PermissionSet.empty();\n  private PermissionSet deniedPermissions = PermissionSet.empty();\n  private boolean grantAll = false;\n\n  public void from(Map<String, Object> params) {\n    Boolean b = (Boolean) params.get(DEBUG_KEY);\n    if (b != null) {\n      debug = b;\n    }\n    b = (Boolean) params.get(TRACK_RETRANSFORMS_KEY);\n    if (b != null) {\n      trackRetransforms = b;\n    }\n    b = (Boolean) params.get(UNSAFE_KEY);\n    if (b != null) {\n      trusted = b;\n    }\n    b = (Boolean) params.get(TRUSTED_KEY);\n    if (b != null) {\n      trusted |= b;\n    }\n    String s = (String) params.get(DUMP_DIR_KEY);\n    if (s != null && !s.isEmpty()) {\n      dumpDir = s;\n    }\n    s = (String) params.get(PROBE_DESC_PATH_KEY);\n    if (s != null && !s.isEmpty()) {\n      probeDescPath = s;\n    }\n\n    s = (String) params.get(Args.BOOT_CLASS_PATH);\n    if (s != null && !s.isEmpty()) {\n      bootClassPath = s;\n    }\n\n    s = (String) params.get(STATSD_HOST_KEY);\n    if (s != null && !s.isEmpty()) {\n      statsdHost = s;\n    }\n    Integer i = (Integer) params.get(STATSD_PORT_KEY);\n    if (i != null) {\n      statsdPort = i;\n    }\n    i = (Integer) params.get(FILEROLL_INTERVAL_KEY);\n    if (i != null) {\n      fileRollMilliseconds = i;\n    }\n    i = (Integer) params.get(FILEROLL_MAXROLLS_KEY);\n    if (i != null) {\n      fileRollMaxRolls = i;\n    }\n    s = (String) params.get(OUTPUT_FILE_KEY);\n    if (s != null && !s.isEmpty()) {\n      outputFile = s;\n    }\n    s = (String) params.get(OUTPUT_DIR_KEY);\n    if (s != null && !s.isEmpty()) {\n      scriptOutputDir = s;\n    }\n    s = (String) params.get(GRANT_PERMISSIONS_KEY);\n    if (s != null && !s.isEmpty()) {\n      grantedPermissions = parsePermissions(s);\n    }\n    s = (String) params.get(DENY_PERMISSIONS_KEY);\n    if (s != null && !s.isEmpty()) {\n      deniedPermissions = parsePermissions(s);\n    }\n    b = (Boolean) params.get(GRANT_ALL_KEY);\n    if (b != null) {\n      grantAll = b;\n    }\n  }\n\n  public static PermissionSet parsePermissions(String permissionString) {\n    if (permissionString == null || permissionString.isEmpty()) {\n      return PermissionSet.empty();\n    }\n    PermissionSet result = PermissionSet.empty();\n    for (String name : permissionString.split(\",\")) {\n      String trimmed = name.trim().toUpperCase();\n      if (!trimmed.isEmpty()) {\n        try {\n          Permission p = Permission.valueOf(trimmed);\n          result = result.with(p);\n        } catch (IllegalArgumentException e) {\n          // Ignore invalid permission names\n        }\n      }\n    }\n    return result;\n  }\n\n  public void from(SharedSettings other) {\n    clientName = other.clientName;\n    debug = other.debug;\n    dumpDir = other.dumpDir;\n    fileRollMilliseconds = other.fileRollMilliseconds;\n    fileRollMaxRolls = other.fileRollMaxRolls;\n    outputFile = other.outputFile;\n    scriptDir = other.scriptDir;\n    scriptOutputDir = other.scriptOutputDir;\n    probeDescPath = other.probeDescPath;\n    bootClassPath = other.bootClassPath;\n    retransformStartup = other.retransformStartup;\n    statsdHost = other.statsdHost;\n    statsdPort = other.statsdPort;\n    trackRetransforms = other.trackRetransforms;\n    trusted = other.trusted;\n    grantedPermissions = other.grantedPermissions;\n    deniedPermissions = other.deniedPermissions;\n    grantAll = other.grantAll;\n  }\n\n  public boolean isDebug() {\n    return debug;\n  }\n\n  public void setDebug(boolean value) {\n    debug = value;\n  }\n\n  public boolean isDumpClasses() {\n    return dumpDir != null;\n  }\n\n  @Deprecated\n  /* @deprecated use {@linkplain SharedSettings#isTrusted()} instead */\n  public boolean isUnsafe() {\n    return trusted;\n  }\n\n  public boolean isTrusted() {\n    return trusted;\n  }\n\n  public void setTrusted(boolean value) {\n    trusted = value;\n  }\n\n  public String getDumpDir() {\n    return dumpDir;\n  }\n\n  public void setDumpDir(String value) {\n    dumpDir = value;\n  }\n\n  public boolean isTrackRetransforms() {\n    return trackRetransforms;\n  }\n\n  public void setTrackRetransforms(boolean value) {\n    trackRetransforms = value;\n  }\n\n  public String getProbeDescPath() {\n    return probeDescPath;\n  }\n\n  public void setProbeDescPath(String probeDescPath) {\n    this.probeDescPath = probeDescPath;\n  }\n\n  public String getBootClassPath() {\n    return bootClassPath;\n  }\n\n  public void setBootClassPath(String bootClassPath) {\n    this.bootClassPath = bootClassPath;\n  }\n\n  public String getStatsdHost() {\n    return statsdHost;\n  }\n\n  public void setStatsdHost(String statsdHost) {\n    this.statsdHost = statsdHost;\n  }\n\n  public int getStatsdPort() {\n    return statsdPort;\n  }\n\n  public void setStatsdPort(int statsdPort) {\n    this.statsdPort = statsdPort;\n  }\n\n  public int getFileRollMilliseconds() {\n    return fileRollMilliseconds;\n  }\n\n  public void setFileRollMilliseconds(int fileRollMilliseconds) {\n    this.fileRollMilliseconds = fileRollMilliseconds;\n  }\n\n  public int getFileRollMaxRolls() {\n    return fileRollMaxRolls;\n  }\n\n  public void setFileRollMaxRolls(int fileRollMaxRolls) {\n    this.fileRollMaxRolls = fileRollMaxRolls;\n  }\n\n  public boolean isRetransformStartup() {\n    return retransformStartup;\n  }\n\n  public void setRetransformStartup(boolean val) {\n    retransformStartup = val;\n  }\n\n  public String getScriptDir() {\n    return scriptDir;\n  }\n\n  public String getOutputFile() {\n    return outputFile;\n  }\n\n  public void setOutputFile(String outputFile) {\n    this.outputFile = outputFile;\n  }\n\n  public String getScriptOutputDir() {\n    return scriptOutputDir;\n  }\n\n  public void setScriptOutputDir(String scriptOutputDir) {\n    this.scriptOutputDir = scriptOutputDir;\n  }\n\n  public String getClientName() {\n    return clientName;\n  }\n\n  public void setClientName(String clientName) {\n    this.clientName = clientName;\n  }\n\n  public PermissionSet getGrantedPermissions() {\n    return grantedPermissions;\n  }\n\n  public void setGrantedPermissions(PermissionSet grantedPermissions) {\n    this.grantedPermissions = grantedPermissions;\n  }\n\n  public PermissionSet getDeniedPermissions() {\n    return deniedPermissions;\n  }\n\n  public void setDeniedPermissions(PermissionSet deniedPermissions) {\n    this.deniedPermissions = deniedPermissions;\n  }\n\n  public boolean isGrantAll() {\n    return grantAll;\n  }\n\n  public void setGrantAll(boolean grantAll) {\n    this.grantAll = grantAll;\n  }\n\n  /**\n   * Computes the effective permissions based on granted, denied, and grantAll settings.\n   *\n   * <p>Logic:\n   *\n   * <ul>\n   *   <li>If grantAll is true, all permissions are granted\n   *   <li>Otherwise, start with standard permissions (default + standard tier)\n   *   <li>Add explicitly granted permissions\n   *   <li>Remove explicitly denied permissions\n   * </ul>\n   *\n   * @return the effective permission set\n   */\n  public PermissionSet getEffectivePermissions() {\n    if (grantAll) {\n      return PermissionSet.all();\n    }\n    PermissionSet effective = PermissionSet.standard();\n    for (Permission p : grantedPermissions) {\n      effective = effective.with(p);\n    }\n    for (Permission p : deniedPermissions) {\n      effective = effective.without(p);\n    }\n    return effective;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/VerifierException.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core;\n\n/**\n * Instance of this exception type is thrown by BTrace Verifier when an input .class is not a valid\n * BTrace program.\n *\n * @author A. Sundararajan\n */\npublic class VerifierException extends RuntimeException {\n  public VerifierException(String msg) {\n    super(msg);\n  }\n\n  public VerifierException(Throwable cause) {\n    super(cause);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/BTrace.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Top-level annotation that identifies a BTrace class.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\npublic @interface BTrace {\n  // If this trace is exposed as MXBean, then this tells\n  // the name of the MXBean.\n  String name() default \"\";\n\n  // description of this trace class.\n  String description() default \"\";\n  // having \"unsafe\" set to true the script will be run in unsafe mode\n\n  @Deprecated\n  /* @deprecated use {@linkplain BTrace#trusted()} instead */\n  boolean unsafe() default false;\n\n  boolean trusted() default false;\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/DTrace.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Annotation for BTrace program to associate a D-script with it. D-script is specified as (inline)\n * String value.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\npublic @interface DTrace {\n  /** \"one-liner\" D-script String */\n  String value();\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/DTraceRef.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Annotation for BTrace program to associate a D-script with it. D-script is referred by a relative\n * or absolute file path.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\npublic @interface DTraceRef {\n  /** Locates D-script by a relative or absolute file path. */\n  String value();\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Duration.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * It is used to mark a probe method argument as the receiver of the duration value<br>\n * Applicable only for {@linkplain OnMethod} annotation with {@linkplain Location} value of\n * {@linkplain Kind#RETURN} or {@linkplain Kind#ERROR}\n *\n * <p>The duration is reported in nanoseconds, using resolution available by OS\n *\n * @author Jaroslav Bachorik jaroslav.bachorik@sun.com\n * @since 1.1\n */\n@Target(ElementType.PARAMETER)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Duration {}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Event.java",
    "content": "package org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport jdk.jfr.Category;\nimport jdk.jfr.Description;\nimport jdk.jfr.Label;\nimport jdk.jfr.Name;\n\n/**\n * Mark a field as a custom event factory.\n *\n * <pre>\n *     <code>\n * \\@Event(name=\"myCustomEvent\", fields={|@Event.Field(type = FieldType.INT, name = \"f1\"), |@Event.Field(type = FieldType.STRING, name = \"f2\"), |@Event.Field(type = FieldType.BOOLEAN, name = \"f3\")})\n * private static JfrEvent myCustomEvent = null;\n *\n * ...\n * \\@OnMethod(...)\n * public static void onprobe() {\n *     JfrEvent event = BTraceUtils.Jfr.prepareEvent(myCustomEvent);\n *     if (event.shouldCommit()) {\n *       BTraceUtils.Jfr.setEventField(event, \"f1\", 10);\n *       BTraceUtils.Jfr.setEventField(event, \"f2\", \"hello\");\n *       BTraceUtils.Jfr.setEventField(event, 2, false);\n *       BTraceUtils.Jfr.commit(event);\n *     }\n * }\n *     </code>\n * </pre>\n *\n * @since 2.1.0\n */\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Event {\n  /** Event field type */\n  enum FieldType {\n    BYTE(\"byte\"),\n    CHAR(\"char\"),\n    SHORT(\"short\"),\n    INT(\"int\"),\n    LONG(\"long\"),\n    FLOAT(\"float\"),\n    DOUBLE(\"double\"),\n    BOOLEAN(\"boolean\"),\n    STRING(\"java.lang.String\"),\n    CLASS(\"java.lang.Class\"),\n    THREAD(\"java.lang.Thread\");\n\n    private final String type;\n\n    FieldType(String type) {\n      this.type = type;\n    }\n\n    public String getType() {\n      return type;\n    }\n  }\n\n  /** Field kind */\n  enum FieldKind {\n    /**\n     * @see jdk.jfr.Timestamp\n     */\n    TIMESTAMP,\n    /**\n     * @see jdk.jfr.Timespan\n     */\n    TIMESPAN,\n    /**\n     * @see jdk.jfr.DataAmount\n     */\n    DATAAMOUNT,\n    /**\n     * @see jdk.jfr.Frequency\n     */\n    FREQUENCY,\n    /**\n     * @see jdk.jfr.MemoryAddress\n     */\n    MEMORYADDRESS,\n    /**\n     * @see jdk.jfr.Percentage\n     */\n    PERCENTAGE,\n    /**\n     * @see jdk.jfr.BooleanFlag\n     */\n    BOOLEANFLAG,\n    /**\n     * @see jdk.jfr.Unsigned\n     */\n    UNSIGNED,\n    /** No additional field kind specification */\n    NONE\n  }\n\n  /** Event field definition */\n  @interface Field {\n    /** Additional field kind */\n    @interface Kind {\n      FieldKind name();\n\n      String value() default \"\";\n    }\n\n    /**\n     * @return field type\n     */\n    FieldType type();\n\n    /**\n     * @return field name\n     */\n    String name();\n\n    /**\n     * @return field label\n     */\n    String label() default \"\";\n\n    /**\n     * @return field description\n     */\n    String description() default \"\";\n\n    /**\n     * @return additional field kind\n     */\n    Kind kind() default @Kind(name = FieldKind.NONE);\n  }\n\n  /**\n   * Event name\n   *\n   * @return event name\n   * @see Name#value()\n   */\n  String name();\n\n  /**\n   * Event label\n   *\n   * @return event label\n   * @see Label#value()\n   */\n  String label() default \"\";\n\n  /**\n   * Event description\n   *\n   * @return event description\n   * @see Description#value()\n   */\n  String description() default \"\";\n\n  /**\n   * Event category\n   *\n   * @return event category\n   * @see Category#value()\n   */\n  String[] category() default \"\";\n\n  /**\n   * Each event should have a stacktrace associated with it\n   *\n   * @return {@literal true} if each event should have a stacktrace associated with it\n   */\n  boolean stacktrace() default true;\n\n  /**\n   * Event fields\n   *\n   * @return event field definitions\n   */\n  Field[] fields();\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Export.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * BTrace fields with this annotation are exposed to out-of-process tools using mechanisms such as\n * jvmstat.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.FIELD)\npublic @interface Export {}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Injected.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Annotates a field as an injected service.\n *\n * @author Jaroslav Bachorik\n */\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Injected {\n  // No parameters by default. Construction is auto-detected by the extension bridge.\n\n  /**\n   * Whether the injected service is optional.\n   * Optional services may fall back to a shim or throwing stub\n   * based on {@link #mode()} or the global property\n   * {@code btrace.extension.shimMode} (shim|throw).\n   */\n  boolean optional() default false;\n\n  /**\n   * Per-field override for fallback behavior when {@link #optional()} is true.\n   * If unspecified, the global property {@code btrace.extension.shimMode}\n   * determines whether to inject a shim or a throwing stub.\n   */\n  InjectionMode mode() default InjectionMode.UNSPECIFIED;\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/InjectionMode.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.core.annotations;\n\n/**\n * Fallback behavior for optional injected services.\n */\npublic enum InjectionMode {\n  /** Use global property to decide. */\n  UNSPECIFIED,\n  /** Inject a no-op shim (production). */\n  SHIM,\n  /** Inject a throwing stub (development). */\n  THROW\n}\n\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Kind.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport org.openjdk.btrace.core.types.AnyType;\n\n/**\n * This enum is specified in the Location annotation to specify probe point kind. This enum\n * identifies various \"points\" of interest within a Java method's bytecode.\n *\n * @author A. Sundararajan\n */\npublic enum Kind {\n  /**\n   *\n   *\n   * <h2>Array element load</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@code type[]} - the array instance\n   *   <li>{@link int int} - array index\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   *   <li>{@linkplain Return} - the return value of the method call (only for {@linkplain\n   *       Where#AFTER})\n   * </ul>\n   */\n  ARRAY_GET,\n\n  /**\n   *\n   *\n   * <h2>Array element store</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@code type[]} - the array instance\n   *   <li>{@link int int} - array index\n   *   <li>{@link java.lang.Object Object} - new value\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   * </ul>\n   */\n  ARRAY_SET,\n\n  /**\n   *\n   *\n   * <h2>Method call</h2>\n   *\n   * <p>The order and number of unannotated parameters (if provided) must fully match the called\n   * method signature. Instead of specific parameter types one can use {@linkplain AnyType} to match\n   * any type.\n   *\n   * <p>If the only unannotated parameter is of type {@link AnyType AnyType[]} it will contain the\n   * called method parameters in the order defined by its signature.\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   *   <li>{@linkplain TargetInstance} - the target instance of the method call or null if the\n   *       method is static\n   *   <li>{@linkplain TargetMethodOrField} - the name of the method which is called\n   *   <li>{@linkplain Return} - the return value of the method call (only for {@linkplain\n   *       Where#AFTER})\n   *   <li>{@linkplain Duration} - the method call duration in nanoseconds (only for {@linkplain\n   *       Where#AFTER}\n   * </ul>\n   */\n  CALL,\n\n  /**\n   *\n   *\n   * <h2>Exception catch</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@link java.lang.Throwable Throwable} - caught throwable\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   * </ul>\n   */\n  CATCH,\n\n  /**\n   *\n   *\n   * <h2>Checkcast</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@link java.lang.String String} - type to cast to\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   *   <li>{@linkplain TargetInstance} - the casted instance ({@linkplain AnyType})\n   * </ul>\n   */\n  CHECKCAST,\n\n  /**\n   *\n   *\n   * <h2>Method entry</h2>\n   *\n   * <p>The order and number of unannotated parameters (if provided) must fully match the probed\n   * method signature. Instead of specific parameter types one can use {@linkplain AnyType} to match\n   * any type.\n   *\n   * <p>If the only unannotated parameter is of type {@link AnyType AnyType[]} it will contain the\n   * probed method parameters in the order defined by its signature.\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   * </ul>\n   */\n  ENTRY,\n\n  /**\n   *\n   *\n   * <h2>\"return\" because of no-catch</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@link java.lang.Throwable Throwable} - the thrown throwable\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   *   <li>{@linkplain Duration} - the method call duration in nanoseconds (only for {@linkplain\n   *       Where#AFTER}\n   * </ul>\n   */\n  ERROR,\n\n  /**\n   *\n   *\n   * <h2>Getting a field value</h2>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   *   <li>{@linkplain TargetInstance} - the field owner instance or null if the field is static\n   *   <li>{@linkplain TargetMethodOrField} - the name of the method which is called\n   *   <li>{@linkplain Return} - the return value of the method call (only for {@linkplain\n   *       Where#AFTER})\n   * </ul>\n   */\n  FIELD_GET,\n\n  /**\n   *\n   *\n   * <h2>Setting a field value</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@link java.lang.Object Object} - new field value\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that field is\n   *       static\n   *   <li>{@linkplain TargetInstance} - the field owner instance or null if the field is static\n   *   <li>{@linkplain TargetMethodOrField} - the name of the method which is called\n   * </ul>\n   */\n  FIELD_SET,\n\n  /**\n   *\n   *\n   * <h2>instanceof check</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@link java.lang.String String} - type to check against\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   *   <li>{@linkplain TargetInstance} - the checked instance ({@linkplain AnyType})\n   * </ul>\n   */\n  INSTANCEOF,\n\n  /**\n   *\n   *\n   * <h2>Source line number</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@link int int} - line number\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   * </ul>\n   */\n  LINE,\n\n  /**\n   *\n   *\n   * <h2>New object created</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@link java.lang.String String} - object type name\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   *   <li>{@linkplain Return} - the return value of the method call (only for {@linkplain\n   *       Where#AFTER})\n   * </ul>\n   */\n  NEW,\n\n  /**\n   *\n   *\n   * <h2>New array created</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@link java.lang.String String} - array type name\n   *   <li>{@link int int} - number of dimensions\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   *   <li>{@linkplain Return} - the return value of the method call (only for {@linkplain\n   *       Where#AFTER})\n   * </ul>\n   */\n  NEWARRAY,\n\n  /**\n   *\n   *\n   * <h2>Return from method</h2>\n   *\n   * <p>The order and number of unannotated probe handler parameters (if provided) must fully match\n   * the probed method signature. Instead of specific parameter types one can use {@linkplain\n   * AnyType} to match any type.\n   *\n   * <p>If the only unannotated parameter is of type {@link AnyType AnyType[]} it will contain the\n   * probed method parameters in the order defined by its signature.\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   *   <li>{@linkplain Return} - the return value of the method call (only for {@linkplain\n   *       Where#AFTER})\n   *   <li>{@linkplain Duration} - the method call duration in nanoseconds (only for {@linkplain\n   *       Where#AFTER}\n   * </ul>\n   */\n  RETURN,\n\n  /**\n   *\n   *\n   * <h2>Entry into a synchronized block</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@link java.lang.Object Object} - lock object\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   * </ul>\n   */\n  SYNC_ENTRY,\n\n  /**\n   *\n   *\n   * <h2>Exit from a synchronized block</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@link java.lang.Object Object} - lock object\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   * </ul>\n   */\n  SYNC_EXIT,\n\n  /**\n   *\n   *\n   * <h2>Throwing an exception</h2>\n   *\n   * <h3>Unannotated probe handler parameters:</h3>\n   *\n   * <ol>\n   *   <li>{@linkplain java.lang.Throwable Throwable} - thrown exception\n   * </ol>\n   *\n   * <h3>Allowed probe handler parameter annotations:</h3>\n   *\n   * <ul>\n   *   <li>{@linkplain ProbeClassName} - the name of the enclosing class\n   *   <li>{@linkplain ProbeMethodName} - the name of the enclosing method\n   *   <li>{@linkplain Self} - the instance enclosing the declaring method or null if that method is\n   *       static\n   * </ul>\n   */\n  THROW\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Level.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.core.annotations;\n\n/**\n * Allows specifying a probe handler instrumentation level matching expression.\n *\n * <p>See {@linkplain Level#value()} for the allowed expression syntax.\n *\n * @author Jaroslav Bachorik\n */\npublic @interface Level {\n  /**\n   * The level check expression.<br>\n   * Allowed syntax is one of the following\n   *\n   * <ul>\n   *   <li>{@code @Level(\"NUMBER\")} - the same as {@code @Level(\">=NUMBER\")}\n   *   <li>{@code @Level(\"=NUMBER\")} - handler is enabled when instrumentation level equals\n   *       <b>NUMBER</b>\n   *   <li>{@code @Level(\">NUMBER\")} - handler is enabled when instrumentation level is greater than\n   *       <b>NUMBER</b>\n   *   <li>{@code @Level(\">=NUMBER\")} - handler is enabled when instrumentation level is greater\n   *       than or equal to <b>NUMBER</b>\n   *   <li>{@code @Level(\"<NUMBER\")} - handler is enabled when instrumentation level is less than\n   *       <b>NUMBER</b>\n   *   <li>{@code @Level(\"<=NUMBER\")} - handler is enabled when instrumentation level is less than\n   *       or equal to <b>NUMBER</b>\n   * </ul>\n   *\n   * <p>Where <b>NUMBER</b> is a non-negative integer number.\n   *\n   * @return the level\n   */\n  String value() default \"\";\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Location.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * This annotation specifies a particular \"location\" within a traced/probed java method for BTrace\n * probe specifications.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface Location {\n  /**\n   * Kind of the location.\n   *\n   * @see Kind\n   */\n  Kind value() default Kind.ENTRY;\n\n  /**\n   * Specifies where do want to probe with respect to the location of interest.\n   *\n   * @see Where\n   */\n  Where where() default Where.BEFORE;\n\n  /** Specifies the fully qualified class name for certain kind of probe locations. */\n  String clazz() default \"\";\n\n  /** Specifies the method name for certain kind of probe locations. */\n  String method() default \"\";\n\n  /**\n   * Specifies the field name for Kind.FIELD_SET and Kind.FIELD_GET probes.\n   *\n   * @see Kind#FIELD_GET\n   * @see Kind#FIELD_SET\n   */\n  String field() default \"\";\n\n  /**\n   * Specifies field or method type for certain kind of probe locations. The type is specified like\n   * in Java source - except the method or field name and parameter names are not included.\n   */\n  String type() default \"\";\n\n  /**\n   * Specifies the line number for Kind.LINE probes.\n   *\n   * @see Kind#LINE\n   */\n  int line() default 0;\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/OnError.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * BTrace method annotated by this annotation is called when any exception is thrown by any of the\n * BTrace action methods.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface OnError {}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/OnEvent.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * BTrace methods annotated by this annotation are called when BTrace client sends \"event\" command.\n * Client may send an event based on some form of user request to send (like pressing Ctrl-C or a\n * GUI menu). String value may used as the name of the event.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface OnEvent {\n  /** The event name. */\n  String value() default \"\";\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/OnExit.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * BTrace method annotated by this annotation is called when BTrace \"exit(int)\" built-in function is\n * called by some other BTrace action method.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface OnExit {}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/OnLowMemory.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * BTrace methods annotated by this annotation are called when the traced JVM's specified memory\n * pool exceeds specified threshold size.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface OnLowMemory {\n  /** The memory pool name. */\n  String pool();\n\n  /** The threashold size to watch for. */\n  long threshold();\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/OnMethod.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n *\n * Copyright (c) 2017, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * This annotation specifies a BTrace probe point by specifying a java class (or classes), a method\n * (or methods in it) and a specific location within it. A BTrace trace action method annotated by\n * this annotation is called when matching the traced program reaches the specified location.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface OnMethod {\n  /**\n   * The probed (or traced) class name. This is either fully qualified name of the class or regular\n   * expression within two forward slash characters [like /java\\\\.awt\\\\..+/]\n   * or @annotation_of_the_class. i.e., specify a class indirectly as a class annotated by specified\n   * annotation.\n   */\n  String clazz();\n\n  /**\n   * The probed (or traced) method name. This is either the name of the method or regular expression\n   * within two forward slash characters [like /read.+/] or @annotation_of_the_method. i.e., specify\n   * a method indirectly as a method annotated by specified annotation.\n   */\n  String method() default \"\";\n\n  /**\n   * When set to {@code true} type checks will not involve assignability checks based on class\n   * hierarchy and only exactly matching types will be resolved as assignable.\n   *\n   * @return {@code true} if exact type matching is requested; {@code false} otherwise (default)\n   */\n  boolean exactTypeMatch() default false;\n\n  /**\n   * This is method type declaration. This is like Java method declaration but not including method\n   * name, parameter names and throws clause. *\n   *\n   * <p>Eg. <b>public void myMethod(java.lang.String param)</b> will become <b><i>void\n   * (java.lang.String)</i></b>\n   */\n  String type() default \"\";\n\n  /** Identifies exact \"location\" or \"point\" of interest to probe within the set of methods. */\n  Location location() default @Location;\n\n  /**\n   * Activate this probe according to instrumentation level.\n   *\n   * <p>It is possible to define enable/disable the handler according to the current instrumentation\n   * level. Eg. {@code @OnMethod(clazz=\"class\", method=\"method\", enableAt=@Level(\">1\")}\n   *\n   * <p>The developer must make sure that all the handlers which are interconnected in any way (eg.\n   * method entry/exit) will be enabled/disabled at a compatible instrumentation level.\n   *\n   * @return The instrumentation level (default {@code @Level(\"0\")})\n   * @see Level\n   * @see org.openjdk.btrace.core.BTraceUtils#getInstrumentationLevel()\n   * @since 1.3.4\n   */\n  Level enableAt() default @Level;\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/OnProbe.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * This annotation is used to specify a BTrace probe point in an abstract fashion instead of\n * specifying the class and the method names. This abstract namespace and (local) name are mapped to\n * one or more concrete probe points by the BTrace agent at runtime.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface OnProbe {\n  /**\n   * Namespace for this abstract (a.k.a logical) probe point. Namespace follows java package name\n   * conventions.\n   */\n  String namespace();\n\n  /** Name within the namespace. Identifies a probe uniquely within the namespace. */\n  String name();\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/OnTimer.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * BTrace methods annotated by this annotation are called when a timer reaches the specified period\n * value. This can be used to run periodic tracing actions.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface OnTimer {\n  /**\n   * Time period of the timer in milliseconds. Defaults to 1 second\n   *\n   * @return timer period\n   */\n  long value() default 1000L;\n\n  /**\n   * If specified the timer period will be taken from btrace arguments. The format is Ant-like\n   * property reference - eg. {@code from = \"${timer}\"}\n   *\n   * @return btrace argument name holding timer period\n   * @since 1.3.11\n   */\n  String from() default \"\";\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/PeriodicEvent.java",
    "content": "package org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport jdk.jfr.Category;\nimport jdk.jfr.Description;\nimport jdk.jfr.Label;\nimport jdk.jfr.Name;\nimport jdk.jfr.Period;\n\n/**\n * Mark a method as a JFR periodic event handler.\n *\n * <pre>\n *     <code>\n * \\@PeriodicEvent(name=\"periodicEvent\", fields=\"boolean hit\", period=\"eachChunk\")\n * public static void periodicEventHandler(JfrEvent periodic) {\n *     BTraceUtils.Jfr.setEventField(periodic, \"hit\", true);\n *     BTraceUtils.Jfr.commit(periodic);\n * }\n *     </code>\n * </pre>\n *\n * @since 2.1.0\n */\n@Target({ElementType.METHOD, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface PeriodicEvent {\n  /**\n   * Event name\n   *\n   * @return event name\n   * @see Name#value()\n   */\n  String name();\n\n  /**\n   * Event label\n   *\n   * @return event label\n   * @see Label#value()\n   */\n  String label() default \"\";\n\n  /**\n   * Event description\n   *\n   * @return event description\n   * @see Description#value()\n   */\n  String description() default \"\";\n\n  /**\n   * Event category\n   *\n   * @return event category\n   * @see Category#value()\n   */\n  String[] category() default \"\";\n\n  /**\n   * Event fields\n   *\n   * @return event field definitions\n   */\n  Event.Field[] fields();\n\n  /**\n   * Event period\n   *\n   * @return event period\n   * @see Period#value()\n   */\n  String period() default \"eachChunk\";\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/ProbeClassName.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * It is used to mark a probe method argument as the receiver of the probe target class name<br>\n * Applicable only for {@linkplain OnMethod} annotation\n *\n * @author Jaroslav Bachorik jaroslav.bachorik@sun.com\n * @since 1.1\n */\n@Target(ElementType.PARAMETER)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface ProbeClassName {}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/ProbeMethodName.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * It is used to mark a probe method argument as the receiver of the probe target class name<br>\n * Applicable only for {@linkplain OnMethod} annotation\n *\n * @author Jaroslav Bachorik jaroslav.bachorik@sun.com\n * @since 1.1\n */\n@Target(ElementType.PARAMETER)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface ProbeMethodName {\n  /** Flag indicating whether a fully qualified name (FQN) or a simple method name should be used */\n  boolean fqn() default false;\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Property.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * BTrace fields with this annotation are exposed as attributes of the dynamic JMX bean that wraps\n * the BTrace class.\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.FIELD)\npublic @interface Property {\n  // by default, the name of the attribute is same as the name\n  // of the field of the BTrace class.\n  String name() default \"\";\n\n  // description of this attribute\n  String description() default \"\";\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Return.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Marks a method parameter as the one that should contain the return value\n *\n * @author Jaroslav Bachorik\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.PARAMETER)\npublic @interface Return {}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Sampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Marks an {@linkplain OnMethod} handler as a sampled one. When a handler is sampled not all events\n * will be traced - only a statistical sample with the given mean.\n *\n * <p>By default an adaptive sampling is used. BTrace will increase or decrease the number of\n * invocations between samples to keep the mean time window, thus decreasing the overall overhead.\n *\n * @author Jaroslav Bachorik\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.CLASS)\npublic @interface Sampled {\n  int MEAN_DEFAULT = 10;\n\n  /**\n   * The sampler kind\n   *\n   * @return The sampler kind\n   */\n  Sampler kind() default Sampler.Const;\n\n  /**\n   * The sampler mean.\n   *\n   * <p>For {@code Sampler.Const} it is the average number of events between samples.<br>\n   * For {@code Sampler.Adaptive} it is the average time (in ns) between samples<br>\n   *\n   * @return The sampler mean\n   */\n  int mean() default MEAN_DEFAULT;\n\n  /**\n   * Specifies the sampler kind\n   *\n   * <ul>\n   *   <li>{@code None} - no sampling\n   *   <li>{@code Const} - keeps the average number of events between samples\n   *   <li>{@code Adaptive} - increases or decreases the average number of events between samples to\n   *       lower overhead\n   * </ul>\n   */\n  enum Sampler {\n    /** No Sampling */\n    None,\n    /** Keeps the average number of events between samples */\n    Const,\n    /** Increases or decreases the average number of events between samples to lower overhead */\n    Adaptive\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Self.java",
    "content": "/*\n * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Marks a method parameter as the one that should contain *this* instance\n *\n * @author Jaroslav Bachorik\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.PARAMETER)\npublic @interface Self {}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/TLS.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Annotation for thread-local BTrace fields. BTrace fields annotated with this annotation are\n * stored in thread local storage. Field get/set are transparently converted to thread local get and\n * set respectively.\n *\n * <h3>Important!!!</h3>\n *\n * It is not possible to access the data stored in the thread local storage from any other handler\n * than {@linkplain OnMethod}\n *\n * @author A. Sundararajan\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.FIELD)\npublic @interface TLS {}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/TargetInstance.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * It is used to mark a probe method argument as the receiver of called instance with {@linkplain\n * Location} value of {@linkplain Kind#CALL}, {@linkplain Kind#FIELD_GET} or {@linkplain\n * Kind#FIELD_SET}.\n *\n * @author Jaroslav Bachorik\n * @since 1.1\n */\n@Target(ElementType.PARAMETER)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface TargetInstance {}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/TargetMethodOrField.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * It is used to mark a probe method argument as the receiver of called method name in {@linkplain\n * Location} = {@linkplain Kind#CALL}\n *\n * @author Jaroslav Bachorik\n * @since 1.1\n */\n@Target(ElementType.PARAMETER)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface TargetMethodOrField {\n  /**\n   * Flag indicating whether a fully qualified name (FQN) or a simple method/field name should be\n   * used\n   */\n  boolean fqn() default false;\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/annotations/Where.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.annotations;\n\n/**\n * This enum is specified in the Location annotation to specify whether a probe point is after or\n * before specific point of interest.\n *\n * @author A. Sundararajan\n */\npublic enum Where {\n  /** after the location of interest */\n  AFTER,\n\n  /** before the location of interest */\n  BEFORE\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/BinaryWireProtocol.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport org.openjdk.btrace.core.comm.v2.BinaryCommand;\nimport org.openjdk.btrace.core.comm.v2.BinaryWireIO;\nimport org.openjdk.btrace.core.comm.v2.CommandAdapter;\n\n/**\n * Wire protocol implementation using custom binary format (V2 protocol).\n *\n * <p>This is the high-performance binary protocol for BTrace that provides significant improvements\n * over Java serialization:\n *\n * <ul>\n *   <li>3-6x faster serialization/deserialization\n *   <li>2-5x smaller payload sizes (10-100x with compression)\n *   <li>Automatic compression for payloads &gt; 1KB\n *   <li>Zero-copy optimizations where possible\n *   <li>Thread-safe with ReentrantLock\n *   <li>Magic byte prefix: 0x42 0x54 0x52 0x32 (\"BTR2\")\n * </ul>\n *\n * <p>This implementation uses {@link BinaryWireIO} for binary serialization and {@link\n * CommandAdapter} to convert between V1 Command objects and V2 BinaryCommand objects, providing a\n * transparent bridge for existing code.\n */\npublic class BinaryWireProtocol implements WireProtocol {\n\n  private final InputStream inputStream;\n  private final OutputStream outputStream;\n  private volatile boolean closed = false;\n\n  /**\n   * Creates a new BinaryWireProtocol instance.\n   *\n   * <p>Note: The input stream should already be positioned after the V2 magic bytes if protocol\n   * negotiation was performed.\n   *\n   * @param inputStream the input stream to read commands from\n   * @param outputStream the output stream to write commands to\n   * @throws IOException if protocol initialization fails\n   */\n  public BinaryWireProtocol(InputStream inputStream, OutputStream outputStream)\n      throws IOException {\n    this.inputStream = inputStream;\n    this.outputStream = outputStream;\n  }\n\n  @Override\n  public Command read() throws IOException {\n    if (closed) {\n      throw new IOException(\"Protocol is closed\");\n    }\n\n    // Read binary command\n    BinaryCommand binaryCmd = BinaryWireIO.read(inputStream);\n\n    // Convert to V1 Command for transparent integration\n    return CommandAdapter.toBtraceCommand(binaryCmd);\n  }\n\n  @Override\n  public void write(Command command) throws IOException {\n    if (closed) {\n      throw new IOException(\"Protocol is closed\");\n    }\n\n    // Convert V1 Command to binary command\n    BinaryCommand binaryCmd = CommandAdapter.toBinaryCommand(command);\n\n    // Write binary command\n    BinaryWireIO.write(outputStream, binaryCmd);\n  }\n\n  @Override\n  public void flush() throws IOException {\n    if (!closed) {\n      outputStream.flush();\n    }\n  }\n\n  @Override\n  public ProtocolVersion getVersion() {\n    return ProtocolVersion.V2;\n  }\n\n  @Override\n  public void close() throws IOException {\n    if (closed) {\n      return;\n    }\n    closed = true;\n\n    IOException exception = null;\n\n    // Close output stream first to flush any pending data\n    try {\n      outputStream.close();\n    } catch (IOException e) {\n      exception = e;\n    }\n\n    // Then close input stream\n    try {\n      inputStream.close();\n    } catch (IOException e) {\n      if (exception == null) {\n        exception = e;\n      } else {\n        exception.addSuppressed(e);\n      }\n    }\n\n    if (exception != null) {\n      throw exception;\n    }\n  }\n\n  /**\n   * Returns the underlying input stream.\n   *\n   * <p>This method is provided for direct access to the stream if needed for advanced use cases.\n   *\n   * @return the InputStream\n   */\n  public InputStream getInputStream() {\n    return inputStream;\n  }\n\n  /**\n   * Returns the underlying output stream.\n   *\n   * <p>This method is provided for direct access to the stream if needed for advanced use cases.\n   *\n   * @return the OutputStream\n   */\n  public OutputStream getOutputStream() {\n    return outputStream;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/Command.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.io.Serializable;\n\npublic abstract class Command implements Serializable {\n  public static final byte ERROR = 0;\n  public static final byte EVENT = 1;\n  public static final byte EXIT = 2;\n  public static final byte INSTRUMENT = 3;\n  public static final byte MESSAGE = 4;\n  public static final byte RENAME = 5;\n  public static final byte STATUS = 6;\n  public static final byte NUMBER_MAP = 7;\n  public static final byte STRING_MAP = 8;\n  public static final byte NUMBER = 9;\n  public static final byte GRID_DATA = 10;\n  public static final byte RETRANSFORMATION_START = 11;\n  public static final byte RETRANSFORM_CLASS = 12;\n  public static final byte SET_PARAMS = 13;\n  public static final byte LIST_PROBES = 14;\n  public static final byte DISCONNECT = 15;\n  public static final byte RECONNECT = 16;\n  public static final byte LIST_FAILED_EXTENSIONS = 17;\n\n  public static final byte FIRST_COMMAND = ERROR;\n  public static final byte LAST_COMMAND = LIST_FAILED_EXTENSIONS;\n\n  @SuppressWarnings(\"RedundantThrows\")\n  public static final Command NULL =\n      new Command() {\n        @Override\n        protected void write(ObjectOutput out) throws IOException {}\n\n        @Override\n        protected void read(ObjectInput in) throws IOException, ClassNotFoundException {}\n      };\n\n  protected byte type;\n  private boolean urgent;\n\n  protected Command(byte type) {\n    this(type, true);\n  }\n\n  protected Command(byte type, boolean urgent) {\n    if (type < FIRST_COMMAND || type > LAST_COMMAND) {\n      throw new IllegalArgumentException();\n    }\n    this.type = type;\n    this.urgent = urgent;\n  }\n\n  private Command() {\n    type = -1;\n    urgent = true;\n  }\n\n  protected abstract void write(ObjectOutput out) throws IOException;\n\n  protected abstract void read(ObjectInput in) throws IOException, ClassNotFoundException;\n\n  public final byte getType() {\n    return type;\n  }\n\n  public final boolean isUrgent() {\n    return urgent;\n  }\n\n  final void setUrgent() {\n    urgent = true;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/CommandListener.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\n\n/**\n * Callback interface called to notify wire protocol commands.\n *\n * @author A. Sundararajan\n */\npublic interface CommandListener {\n  void onCommand(Command cmd) throws IOException;\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/DataCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\n/**\n * Command that carries arbitrary \"result/output\" data.\n *\n * @author A. Sundararajan\n */\npublic abstract class DataCommand extends Command implements PrintableCommand {\n  protected String name;\n\n  public DataCommand(byte type, String name, boolean urgent) {\n    super(type, urgent);\n    this.name = name;\n  }\n\n  public String getName() {\n    return name;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/DisconnectCommand.java",
    "content": "package org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.io.PrintWriter;\n\n/**\n * @since WireIO v.1\n */\npublic final class DisconnectCommand extends Command implements PrintableCommand {\n  private String probeId = \"\";\n\n  public DisconnectCommand() {\n    super(Command.DISCONNECT, true);\n  }\n\n  public DisconnectCommand(String probeId) {\n    super(Command.DISCONNECT, true);\n    this.probeId = probeId;\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeUTF(probeId);\n  }\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    probeId = in.readUTF();\n  }\n\n  public void setProbeId(String probeId) {\n    this.probeId = probeId;\n  }\n\n  public String getProbeId() {\n    return probeId;\n  }\n\n  @Override\n  public void print(PrintWriter out) {\n    out.println(\"BTrace Probe: \" + probeId);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/ErrorCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.io.PrintWriter;\n\npublic class ErrorCommand extends Command implements PrintableCommand {\n  private Throwable cause;\n\n  public ErrorCommand(Throwable cause) {\n    super(ERROR, true);\n    this.cause = cause;\n  }\n\n  protected ErrorCommand() {\n    this(null);\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeObject(cause);\n  }\n\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    Object obj = in.readObject();\n    if (obj != null && !(obj instanceof Throwable)) {\n      throw new IOException(\n          \"Invalid data type: expected Throwable, got \" + obj.getClass().getName());\n    }\n    cause = (Throwable) obj;\n  }\n\n  public Throwable getCause() {\n    return cause;\n  }\n\n  @Override\n  public void print(PrintWriter out) {\n    out.append(\"! ERROR\\n\");\n    Throwable cause = getCause();\n    if (cause != null) {\n      cause.printStackTrace(out);\n    } else {\n      out.append(\"(No exception information available)\\n\");\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/EventCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\n\npublic class EventCommand extends Command {\n  private String event;\n\n  public EventCommand(String event) {\n    super(EVENT, true);\n    this.event = event;\n  }\n\n  protected EventCommand() {\n    this(null);\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeUTF(event);\n  }\n\n  @Override\n  protected void read(ObjectInput in) throws ClassNotFoundException, IOException {\n    event = in.readUTF();\n  }\n\n  public String getEvent() {\n    return event;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/ExitCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\n\npublic class ExitCommand extends Command {\n  private int exitCode;\n\n  public ExitCommand(int exitCode) {\n    super(EXIT, true);\n    this.exitCode = exitCode;\n  }\n\n  protected ExitCommand() {\n    this(0);\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeInt(exitCode);\n  }\n\n  @Override\n  protected void read(ObjectInput in) throws IOException {\n    exitCode = in.readInt();\n  }\n\n  public int getExitCode() {\n    return exitCode;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/GridDataCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Pattern;\n\n/**\n * A data command that holds tabular data.\n *\n * <p>The elements contained within the grid must be of type Number or String.\n *\n * @author Christian Glencross\n */\npublic class GridDataCommand extends DataCommand {\n  private static final Pattern INDEX_PATTERN = Pattern.compile(\"%(\\\\d)+\\\\$\");\n  private static final HashMap<Class<?>, String> typeFormats = new HashMap<>();\n\n  static {\n    typeFormats.put(Integer.class, \"%15d\");\n    typeFormats.put(Short.class, \"%15d\");\n    typeFormats.put(Byte.class, \"%15d\");\n    typeFormats.put(Long.class, \"%15d\");\n    typeFormats.put(BigInteger.class, \"%15d\");\n    typeFormats.put(Double.class, \"%15f\");\n    typeFormats.put(Float.class, \"%15f\");\n    typeFormats.put(BigDecimal.class, \"%15f\");\n    typeFormats.put(String.class, \"%-50s\");\n  }\n\n  private List<String> columnNames;\n  private List<Object[]> data;\n  private String format;\n\n  /**\n   * Used when deserializing a {@linkplain GridDataCommand} instance.<br>\n   * The instance is then initialized by calling the {@linkplain\n   * GridDataCommand#read(java.io.ObjectInput) } method\n   */\n  public GridDataCommand() {\n    this(null, null);\n  }\n\n  /**\n   * Creates a new instance of {@linkplain GridDataCommand} with implicit format\n   *\n   * @param name The aggregation name\n   * @param data The aggregation data\n   */\n  public GridDataCommand(String name, List<Object[]> data) {\n    this(name, null, data, null);\n  }\n\n  /**\n   * Creates a new instance of {@linkplain GridDataCommand} with explicit format\n   *\n   * @param name The aggregation name\n   * @param data The aggregation data\n   * @param format The format to use. It mimics {@linkplain String#format(java.lang.String,\n   *     java.lang.Object[]) } behaviour with the addition of the ability to address the key title\n   *     as a 0-indexed item\n   * @see String#format(java.lang.String, java.lang.Object[])\n   */\n  public GridDataCommand(String name, List<Object[]> data, String format) {\n    this(name, null, data, format);\n  }\n\n  public GridDataCommand(String name, List<String> columnNames, List<Object[]> data) {\n    this(name, columnNames, data, null);\n  }\n\n  public GridDataCommand(String name, List<String> columnNames, List<Object[]> data, String format) {\n    super(GRID_DATA, name, false);\n    this.columnNames = columnNames != null ? new ArrayList<>(columnNames) : null;\n    this.data = data;\n    this.format = format;\n  }\n\n  public List<Object[]> getData() {\n    return data;\n  }\n\n  public List<String> getColumnNames() {\n    return columnNames != null ? new ArrayList<>(columnNames) : null;\n  }\n\n  /**\n   * Calculates the necessary field width of each column\n   *\n   * @param objects a list of objects\n   * @return a map containing as key the column number and as value the width of the longest value\n   */\n  private Map<Integer, Integer> getColumnWidth(List<Object[]> objects) {\n    Map<Integer, Integer> columnWidth = new LinkedHashMap<>();\n    for (Object[] obj : objects) {\n      if (obj == null) {\n        continue;\n      }\n      for (int column = 0; column < obj.length; ++column) {\n        int length = obj[column].toString().length();\n        Integer width = 0;\n        if (columnWidth.containsKey(column)) {\n          width = columnWidth.get(column);\n        }\n        if (length > width) {\n          columnWidth.put(column, length);\n        }\n      }\n    }\n    return columnWidth;\n  }\n\n  @Override\n  public void print(PrintWriter out) {\n    if (data != null) {\n      if (name != null && !name.isEmpty()) {\n        out.println(name);\n      }\n      Map<Integer, Integer> columnWidth = getColumnWidth(data);\n      for (Object[] dataRow : data) {\n        if (dataRow == null) {\n          continue;\n        }\n        // Pretty-print multi-line text\n        Object[] printRow = dataRow.clone();\n        for (int i = 0; i < printRow.length; i++) {\n          if (printRow[i] == null) {\n            printRow[i] = \"<null>\";\n          }\n          if (printRow[i] instanceof String) {\n            String value = (String) printRow[i];\n            if (value.contains(\"\\n\")) {\n              printRow[i] = reformatMultilineValue(value);\n            }\n          }\n        }\n\n        // Format the text\n        String usedFormat = format;\n        if (usedFormat == null || usedFormat.length() == 0) {\n          StringBuilder buffer = new StringBuilder();\n          for (int i = 0; i < printRow.length; i++) {\n            buffer.append(\"  \");\n            buffer.append(getFormat(printRow[i], columnWidth, i));\n          }\n          usedFormat = buffer.toString();\n        }\n        String line = String.format(usedFormat, printRow);\n\n        out.println(line);\n      }\n    }\n    out.flush();\n  }\n\n  /**\n   * Get the format of an object\n   *\n   * @param object get the format of this object\n   * @param columnWidth a map containing as key the column number and as value the width of the\n   *     longest value\n   * @param column get the format of that column number\n   * @return the format of an object\n   */\n  private String getFormat(Object object, Map<Integer, Integer> columnWidth, Integer column) {\n    if (object == null) {\n      return \"%-15s\";\n    }\n    String usedFormat = typeFormats.get(object.getClass());\n    if (usedFormat == null) {\n      return \"%-15s\";\n    }\n    if (columnWidth != null && column != null && columnWidth.containsKey(column)) {\n      usedFormat = usedFormat.replaceFirst(\"\\\\d+\", String.valueOf(columnWidth.get(column)));\n    }\n    return usedFormat;\n  }\n\n  /**\n   * Takes a multi-line value, prefixes and appends a blank line, and inserts tab characters at the\n   * start of every line. This is derived from how dtrace displays stack traces, and it makes for\n   * pretty readable output.\n   */\n  private String reformatMultilineValue(String value) {\n    StringBuilder result = new StringBuilder();\n    result.append(\"\\n\");\n    for (String line : value.split(\"\\n\")) {\n      result.append(\"\\t\").append(line);\n      result.append(\"\\n\");\n    }\n    return result.toString();\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeUTF(name != null ? name : \"\");\n    out.writeUTF(format != null ? format : \"\");\n    if (columnNames != null) {\n      out.writeInt(columnNames.size());\n      for (String columnName : columnNames) {\n        out.writeUTF(columnName != null ? columnName : \"\");\n      }\n    } else {\n      out.writeInt(0);\n    }\n    if (data != null) {\n      out.writeInt(data.size());\n      for (Object[] row : data) {\n        out.writeInt(row.length);\n        for (Object cell : row) {\n          out.writeObject(cell);\n        }\n      }\n    } else {\n      out.writeInt(0);\n    }\n  }\n\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    name = in.readUTF();\n    format = in.readUTF();\n    if (format.length() == 0) format = null;\n\n    int columnCount = in.readInt();\n    columnNames = new ArrayList<>(columnCount);\n    for (int i = 0; i < columnCount; i++) {\n      String columnName = in.readUTF();\n      columnNames.add(columnName.length() == 0 ? null : columnName);\n    }\n\n    int rowCount = in.readInt();\n    data = new ArrayList<>(rowCount);\n    for (int i = 0; i < rowCount; i++) {\n      int cellCount = in.readInt();\n      Object[] row = new Object[cellCount];\n      for (int j = 0; j < cellCount; j++) {\n        row[j] = in.readObject();\n      }\n      data.add(row);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/InstrumentCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.util.Map;\nimport org.openjdk.btrace.core.ArgsMap;\n\npublic class InstrumentCommand extends Command {\n\n  private byte[] code;\n  private ArgsMap args;\n\n  public InstrumentCommand(byte[] code, ArgsMap args) {\n    super(INSTRUMENT, true);\n    // Defensive copy of bytecode array to prevent external modification\n    this.code = code != null ? code.clone() : null;\n    // Create new ArgsMap by copying entries to prevent external modification\n    if (args != null) {\n      this.args = new ArgsMap(args.size());\n      for (Map.Entry<String, String> entry : args) {\n        this.args.put(entry.getKey(), entry.getValue());\n      }\n    } else {\n      this.args = null;\n    }\n  }\n\n  public InstrumentCommand(byte[] code, String[] args) {\n    this(code, new ArgsMap(args));\n  }\n\n  public InstrumentCommand(byte[] code, Map<String, String> args) {\n    this(code, new ArgsMap(args));\n  }\n\n  protected InstrumentCommand() {\n    this(null, (Map<String, String>) null);\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeInt(code.length);\n    out.write(code);\n    out.writeInt(args.size());\n    for (Map.Entry<String, String> e : args) {\n      out.writeUTF(e.getKey());\n      String val = e.getValue();\n      out.writeUTF(val != null ? val : \"\");\n    }\n  }\n\n  @Override\n  protected void read(ObjectInput in) throws IOException {\n    int len = in.readInt();\n    code = new byte[len];\n    in.readFully(code);\n    len = in.readInt();\n    args = new ArgsMap(len);\n    for (int i = 0; i < len; i++) {\n      String key = in.readUTF();\n      String val = in.readUTF();\n      args.put(key, val);\n    }\n  }\n\n  public byte[] getCode() {\n    return code != null ? code.clone() : null;\n  }\n\n  public ArgsMap getArguments() {\n    return args;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/JavaSerializationProtocol.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.io.OutputStream;\n\n/**\n * Wire protocol implementation using Java Object Serialization (V1 protocol).\n *\n * <p>This is the original BTrace wire protocol that uses ObjectInputStream/ObjectOutputStream for\n * command serialization. It provides broad compatibility but has performance limitations compared\n * to the binary protocol (V2).\n *\n * <p>Characteristics:\n *\n * <ul>\n *   <li>Uses standard Java serialization\n *   <li>Compatible with all BTrace versions\n *   <li>No magic byte prefix\n *   <li>Larger payload sizes\n *   <li>Slower serialization/deserialization\n *   <li>Synchronized write operations\n * </ul>\n *\n * <p>This implementation wraps the legacy {@link WireIO} class to provide the {@link WireProtocol}\n * interface.\n */\npublic class JavaSerializationProtocol implements WireProtocol {\n\n  private final ObjectInputStream ois;\n  private final ObjectOutputStream oos;\n  private volatile boolean closed = false;\n\n  /**\n   * Creates a new JavaSerializationProtocol instance.\n   *\n   * @param inputStream the input stream to read commands from\n   * @param outputStream the output stream to write commands to\n   * @throws IOException if stream initialization fails\n   */\n  public JavaSerializationProtocol(InputStream inputStream, OutputStream outputStream)\n      throws IOException {\n    // ObjectOutputStream must be created BEFORE ObjectInputStream\n    // to avoid deadlock with stream headers. If ObjectInputStream creation fails,\n    // ensure the already-created ObjectOutputStream is closed to avoid resource leak.\n    ObjectOutputStream tempOos = null;\n    try {\n      tempOos = new ObjectOutputStream(outputStream);\n      tempOos.flush(); // Write stream header immediately\n      this.oos = tempOos;\n      this.ois = new ObjectInputStream(inputStream);\n    } catch (IOException e) {\n      if (tempOos != null) {\n        try {\n          tempOos.close();\n        } catch (IOException closeEx) {\n          e.addSuppressed(closeEx);\n        }\n      }\n      throw e;\n    }\n  }\n\n  /**\n   * Creates a JavaSerializationProtocol with existing ObjectStreams.\n   *\n   * <p>This constructor is provided for backward compatibility with code that already has\n   * ObjectInputStream/ObjectOutputStream instances.\n   *\n   * @param ois the ObjectInputStream to read from\n   * @param oos the ObjectOutputStream to write to\n   */\n  public JavaSerializationProtocol(ObjectInputStream ois, ObjectOutputStream oos) {\n    this.ois = ois;\n    this.oos = oos;\n  }\n\n  @Override\n  public Command read() throws IOException, ClassNotFoundException {\n    if (closed) {\n      throw new IOException(\"Protocol is closed\");\n    }\n    return WireIO.read(ois);\n  }\n\n  @Override\n  public void write(Command command) throws IOException {\n    if (closed) {\n      throw new IOException(\"Protocol is closed\");\n    }\n    oos.reset();\n    WireIO.write(oos, command);\n  }\n\n  @Override\n  public void flush() throws IOException {\n    if (!closed) {\n      oos.flush();\n    }\n  }\n\n  @Override\n  public ProtocolVersion getVersion() {\n    return ProtocolVersion.V1;\n  }\n\n  @Override\n  public void close() throws IOException {\n    if (closed) {\n      return;\n    }\n    closed = true;\n\n    IOException exception = null;\n\n    // Close output stream first to flush any pending data\n    try {\n      oos.close();\n    } catch (IOException e) {\n      exception = e;\n    }\n\n    // Then close input stream\n    try {\n      ois.close();\n    } catch (IOException e) {\n      if (exception == null) {\n        exception = e;\n      } else {\n        exception.addSuppressed(e);\n      }\n    }\n\n    if (exception != null) {\n      throw exception;\n    }\n  }\n\n  /**\n   * Returns the underlying ObjectInputStream.\n   *\n   * <p>This method is provided for backward compatibility with code that needs direct access to the\n   * ObjectInputStream.\n   *\n   * @return the ObjectInputStream\n   */\n  public ObjectInputStream getObjectInputStream() {\n    return ois;\n  }\n\n  /**\n   * Returns the underlying ObjectOutputStream.\n   *\n   * <p>This method is provided for backward compatibility with code that needs direct access to the\n   * ObjectOutputStream.\n   *\n   * @return the ObjectOutputStream\n   */\n  public ObjectOutputStream getObjectOutputStream() {\n    return oos;\n  }\n\n  /**\n   * Resets the ObjectOutputStream state.\n   *\n   * <p>This method is useful for preventing memory leaks in long-running connections by clearing\n   * the stream's object cache. It should be called periodically between writes.\n   *\n   * @throws IOException if an I/O error occurs\n   */\n  public void reset() throws IOException {\n    if (!closed) {\n      oos.reset();\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/ListFailedExtensionsCommand.java",
    "content": "package org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\n/**\n * Command to list extensions that failed to load during BTrace agent initialization.\n *\n * @since WireIO v.1\n */\npublic class ListFailedExtensionsCommand extends Command implements PrintableCommand {\n  // List of \"extensionClassName: errorMessage\" entries\n  private final List<String> failedExtensions = new CopyOnWriteArrayList<>();\n\n  public ListFailedExtensionsCommand() {\n    super(Command.LIST_FAILED_EXTENSIONS, true);\n  }\n\n  public void setFailedExtensions(Map<String, String> failures) {\n    this.failedExtensions.clear();\n    if (failures != null && !failures.isEmpty()) {\n      for (Map.Entry<String, String> entry : failures.entrySet()) {\n        failedExtensions.add(entry.getKey() + \": \" + entry.getValue());\n      }\n    }\n  }\n\n  public void setFailedExtensionsList(List<String> failures) {\n    this.failedExtensions.clear();\n    if (failures != null && !failures.isEmpty()) {\n      this.failedExtensions.addAll(failures);\n    }\n  }\n\n  public List<String> getFailedExtensions() {\n    return new ArrayList<>(failedExtensions);\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeInt(failedExtensions.size());\n    for (String failure : failedExtensions) {\n      out.writeUTF(failure);\n    }\n  }\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    int count = in.readInt();\n    for (int i = 0; i < count; i++) {\n      failedExtensions.add(in.readUTF());\n    }\n  }\n\n  @Override\n  public void print(PrintWriter out) {\n    if (failedExtensions.isEmpty()) {\n      out.println(\"No extension failures detected.\");\n    } else {\n      out.println(\"Failed Extensions:\");\n      int cntr = 1;\n      for (String failure : failedExtensions) {\n        out.println(\"  \" + cntr++ + \". \" + failure);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/ListProbesCommand.java",
    "content": "package org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.io.PrintWriter;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\n/**\n * @since WireIO v.1\n */\npublic class ListProbesCommand extends Command implements PrintableCommand {\n  // CopyOnWriteArrayList ensures safe iteration during concurrent updates without CME\n  private final List<String> probes = new CopyOnWriteArrayList<>();\n\n  public ListProbesCommand() {\n    super(Command.LIST_PROBES, true);\n  }\n\n  public void setProbes(Collection<String> probes) {\n    this.probes.clear();\n    if (probes != null && !probes.isEmpty()) {\n      this.probes.addAll(probes);\n    }\n  }\n\n  public List<String> getProbes() {\n    return new ArrayList<>(probes);\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeInt(probes.size());\n    for (String probe : probes) {\n      out.writeUTF(probe);\n    }\n  }\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    int numProbes = in.readInt();\n    for (int i = 0; i < numProbes; i++) {\n      probes.add(in.readUTF());\n    }\n  }\n\n  @Override\n  public void print(PrintWriter out) {\n    int cntr = 1;\n    for (String probe : probes) {\n      out.println(cntr++ + \": \" + probe);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/MessageCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.io.PrintWriter;\nimport java.nio.charset.StandardCharsets;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class MessageCommand extends DataCommand {\n  private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT =\n      ThreadLocal.withInitial(() -> new SimpleDateFormat(\"HH:mm:ss:SSS\"));\n\n  private long time;\n  private String msg;\n\n  public MessageCommand(long time, String msg) {\n    this(time, msg, false);\n  }\n\n  public MessageCommand(long time, String msg, boolean urgent) {\n    super(MESSAGE, null, urgent);\n    this.time = time;\n    this.msg = msg;\n  }\n\n  public MessageCommand(String msg) {\n    this(msg, false);\n  }\n\n  public MessageCommand(String msg, boolean urgent) {\n    this(0L, msg, urgent);\n  }\n\n  protected MessageCommand() {\n    this(0L, null);\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeBoolean(isUrgent());\n    out.writeLong(time);\n    byte[] bytes = msg != null ? msg.getBytes(StandardCharsets.UTF_8) : new byte[0];\n    out.writeInt(bytes.length);\n    if (bytes.length > 0) {\n      out.write(bytes);\n    }\n  }\n\n  @Override\n  protected void read(ObjectInput in) throws ClassNotFoundException, IOException {\n    if (in.readBoolean()) {\n      setUrgent();\n    }\n    time = in.readLong();\n    int len = in.readInt();\n    byte[] bytes = new byte[len];\n\n    int ptr = 0;\n    while (ptr < len) {\n      int bytesRead = in.read(bytes, ptr, len - ptr);\n      if (bytesRead == -1) {\n        throw new IOException(\"Unexpected end of stream\");\n      }\n      ptr += bytesRead;\n    }\n\n    msg = new String(bytes, StandardCharsets.UTF_8);\n  }\n\n  public long getTime() {\n    return time;\n  }\n\n  public String getMessage() {\n    return msg;\n  }\n\n  @Override\n  public void print(PrintWriter out) {\n    if (time != 0L) {\n      out.print(DATE_FORMAT.get().format(new Date(time)));\n      out.print(\" : \");\n    }\n    if (msg != null) {\n      out.println(msg);\n    }\n    if (isUrgent()) {\n      out.flush();\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/NumberDataCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.io.PrintWriter;\n\n/**\n * A simple data command that has one number value.\n *\n * @author A. Sundararajan\n */\npublic class NumberDataCommand extends DataCommand {\n  private Number value;\n\n  public NumberDataCommand() {\n    this(null, 0);\n  }\n\n  public NumberDataCommand(String name, Number value) {\n    super(NUMBER, name, false);\n    this.value = value;\n  }\n\n  @Override\n  public void print(PrintWriter out) {\n    if (name != null && !name.isEmpty()) {\n      out.print(name);\n      out.print(\" = \");\n    }\n    out.println(value);\n  }\n\n  public Number getValue() {\n    return value;\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeUTF(name != null ? name : \"\");\n    out.writeObject(value);\n  }\n\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    name = in.readUTF();\n    Object obj = in.readObject();\n    if (obj != null && !(obj instanceof Number)) {\n      throw new IOException(\n          \"Invalid data type: expected Number, got \" + obj.getClass().getName());\n    }\n    value = (Number) obj;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/NumberMapDataCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.io.PrintWriter;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * A data command that hold data of type Map&lt;String, Number&gt;.\n *\n * @author A. Sundararajan\n */\npublic class NumberMapDataCommand extends DataCommand {\n\n  private Map<String, ? extends Number> data;\n\n  public NumberMapDataCommand() {\n    this(null, null);\n  }\n\n  public NumberMapDataCommand(String name, Map<String, ? extends Number> data) {\n    super(NUMBER_MAP, name, false);\n    this.data = (data != null) ? new HashMap<String, Number>(data) : null;\n  }\n\n  public Map<String, ? extends Number> getData() {\n    return data;\n  }\n\n  @Override\n  public void print(PrintWriter out) {\n    if (name != null && !name.isEmpty()) {\n      out.println(name);\n    }\n    if (data != null) {\n      for (Map.Entry<String, ? extends Number> e : data.entrySet()) {\n        out.print(e.getKey());\n        out.print(\" = \");\n        out.println(e.getValue());\n      }\n    }\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeUTF(name != null ? name : \"\");\n    if (data != null) {\n      out.writeInt(data.size());\n      for (String key : data.keySet()) {\n        out.writeUTF(key);\n        out.writeObject(data.get(key));\n      }\n    } else {\n      out.writeInt(0);\n    }\n  }\n\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    name = in.readUTF();\n    Map<String, Number> map = new HashMap<>();\n    int sz = in.readInt();\n    for (int i = 0; i < sz; i++) {\n      map.put(in.readUTF(), (Number) in.readObject());\n    }\n    data = map;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/PrintableCommand.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.PrintWriter;\n\n/**\n * Marks any command which is able to print its internal info into the provided {@linkplain\n * PrintWriter}\n *\n * @author Jaroslav Bachorik\n */\npublic interface PrintableCommand {\n  /**\n   * Print the command internal info\n   *\n   * @param out the associated {@linkplain PrintWriter}\n   */\n  void print(PrintWriter out);\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/ProtocolConfig.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\n/**\n * Configuration for BTrace wire protocol.\n *\n * <p>This class provides centralized configuration for protocol version selection and negotiation\n * behavior. Configuration can be set via system properties or programmatically.\n *\n * <p>System properties:\n *\n * <ul>\n *   <li><b>btrace.comm.protocol</b> - Sets the protocol version (1 or 2, or \"v1\"/\"v2\"). Default:\n *       v2\n *   <li><b>btrace.comm.autoNegotiate</b> - Enable automatic protocol negotiation. Default: true\n *   <li><b>btrace.comm.forceVersion</b> - Force a specific version without negotiation. Default:\n *       false\n * </ul>\n *\n * <p>Usage example:\n *\n * <pre>\n * // Use default configuration (V2 with auto-negotiation)\n * ProtocolConfig config = ProtocolConfig.getDefault();\n *\n * // Force V1 protocol\n * ProtocolConfig config = ProtocolConfig.builder()\n *     .version(ProtocolVersion.V1)\n *     .autoNegotiate(false)\n *     .build();\n *\n * // Use system properties\n * System.setProperty(\"btrace.comm.protocol\", \"v1\");\n * ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n * </pre>\n */\npublic class ProtocolConfig {\n\n  private static final String PROP_PROTOCOL = \"btrace.comm.protocol\";\n  private static final String PROP_AUTO_NEGOTIATE = \"btrace.comm.autoNegotiate\";\n  private static final String PROP_FORCE_VERSION = \"btrace.comm.forceVersion\";\n\n  private final ProtocolVersion version;\n  private final boolean autoNegotiate;\n  private final boolean forceVersion;\n\n  private ProtocolConfig(ProtocolVersion version, boolean autoNegotiate, boolean forceVersion) {\n    this.version = version;\n    this.autoNegotiate = autoNegotiate;\n    this.forceVersion = forceVersion;\n\n    if (forceVersion && autoNegotiate) {\n      throw new IllegalArgumentException(\n          \"Cannot force version and enable auto-negotiation at the same time\");\n    }\n  }\n\n  /**\n   * Returns the configured protocol version.\n   *\n   * @return the protocol version to use\n   */\n  public ProtocolVersion getVersion() {\n    return version;\n  }\n\n  /**\n   * Returns whether automatic protocol negotiation is enabled.\n   *\n   * @return true if auto-negotiation is enabled, false otherwise\n   */\n  public boolean isAutoNegotiate() {\n    return autoNegotiate;\n  }\n\n  /**\n   * Returns whether to force the configured version without negotiation.\n   *\n   * @return true if version should be forced, false otherwise\n   */\n  public boolean isForceVersion() {\n    return forceVersion;\n  }\n\n  /**\n   * Returns the default configuration.\n   *\n   * <p>Default: V2 protocol with auto-negotiation enabled.\n   *\n   * @return the default ProtocolConfig\n   */\n  public static ProtocolConfig getDefault() {\n    return builder().build();\n  }\n\n  /**\n   * Creates a configuration from system properties.\n   *\n   * @return a ProtocolConfig based on system properties, or default if not set\n   */\n  public static ProtocolConfig fromSystemProperties() {\n    Builder builder = builder();\n\n    String protocolProp = System.getProperty(PROP_PROTOCOL);\n    if (protocolProp != null) {\n      builder.version(parseProtocolVersion(protocolProp));\n    }\n\n    String autoNegotiateProp = System.getProperty(PROP_AUTO_NEGOTIATE);\n    if (autoNegotiateProp != null) {\n      builder.autoNegotiate(Boolean.parseBoolean(autoNegotiateProp));\n    }\n\n    String forceVersionProp = System.getProperty(PROP_FORCE_VERSION);\n    if (forceVersionProp != null) {\n      builder.forceVersion(Boolean.parseBoolean(forceVersionProp));\n    }\n\n    return builder.build();\n  }\n\n  /**\n   * Parses a protocol version string.\n   *\n   * @param value the version string (\"1\", \"2\", \"v1\", \"v2\", \"V1\", \"V2\")\n   * @return the corresponding ProtocolVersion\n   * @throws IllegalArgumentException if the version string is invalid\n   */\n  private static ProtocolVersion parseProtocolVersion(String value) {\n    if (value == null || value.trim().isEmpty()) {\n      return ProtocolVersion.getDefault();\n    }\n\n    String normalized = value.trim().toLowerCase();\n\n    switch (normalized) {\n      case \"1\":\n      case \"v1\":\n        return ProtocolVersion.V1;\n      case \"2\":\n      case \"v2\":\n        return ProtocolVersion.V2;\n      default:\n        throw new IllegalArgumentException(\"Invalid protocol version: \" + value);\n    }\n  }\n\n  /**\n   * Creates a new builder for ProtocolConfig.\n   *\n   * @return a new Builder instance\n   */\n  public static Builder builder() {\n    return new Builder();\n  }\n\n  @Override\n  public String toString() {\n    return \"ProtocolConfig{\"\n        + \"version=\"\n        + version\n        + \", autoNegotiate=\"\n        + autoNegotiate\n        + \", forceVersion=\"\n        + forceVersion\n        + '}';\n  }\n\n  /** Builder for ProtocolConfig. */\n  public static class Builder {\n    private ProtocolVersion version = ProtocolVersion.getDefault();\n    private boolean autoNegotiate = true;\n    private boolean forceVersion = false;\n\n    private Builder() {}\n\n    /**\n     * Sets the protocol version.\n     *\n     * @param version the protocol version to use\n     * @return this builder\n     */\n    public Builder version(ProtocolVersion version) {\n      this.version = version;\n      return this;\n    }\n\n    /**\n     * Sets whether to enable automatic protocol negotiation.\n     *\n     * @param autoNegotiate true to enable auto-negotiation, false otherwise\n     * @return this builder\n     */\n    public Builder autoNegotiate(boolean autoNegotiate) {\n      this.autoNegotiate = autoNegotiate;\n      return this;\n    }\n\n    /**\n     * Sets whether to force the configured version without negotiation.\n     *\n     * @param forceVersion true to force version, false otherwise\n     * @return this builder\n     */\n    public Builder forceVersion(boolean forceVersion) {\n      this.forceVersion = forceVersion;\n      return this;\n    }\n\n    /**\n     * Builds the ProtocolConfig.\n     *\n     * @return a new ProtocolConfig instance\n     * @throws IllegalArgumentException if configuration is invalid\n     */\n    public ProtocolConfig build() {\n      return new ProtocolConfig(version, autoNegotiate, forceVersion);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/ProtocolNegotiator.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.PushbackInputStream;\nimport java.util.Arrays;\n\n/**\n * Handles protocol version negotiation for BTrace command communication.\n *\n * <p>Protocol negotiation happens ONCE PER CONNECTION by examining the first few bytes from the\n * stream. The negotiator detects which protocol version is being used based on magic byte prefixes:\n *\n * <ul>\n *   <li>V2: Starts with 0x42 0x54 0x52 0x32 (\"BTR2\")\n *   <li>V1: No magic bytes, uses Java serialization format\n * </ul>\n *\n * <p>Usage example:\n *\n * <pre>\n * InputStream is = socket.getInputStream();\n * ProtocolNegotiator negotiator = new ProtocolNegotiator();\n * ProtocolVersion version = negotiator.negotiate(is);\n *\n * if (version == ProtocolVersion.V2) {\n *   // Use binary protocol\n *   BinaryCommand cmd = BinaryWireIO.read(is);\n * } else {\n *   // Use Java serialization\n *   Command cmd = WireIO.read(new ObjectInputStream(is));\n * }\n * </pre>\n */\npublic class ProtocolNegotiator {\n\n  /** Maximum size of magic byte prefix to detect */\n  private static final int MAX_MAGIC_BYTES = 4; // Length of \"BTR2\"\n  private static final String PROP_NEGOTIATION_TIMEOUT = \"btrace.protocol.negotiation.timeout\";\n  private static final int DEFAULT_NEGOTIATION_TIMEOUT_MS = 5000;\n\n  private final ProtocolVersion preferredVersion;\n\n  /** Creates a negotiator with the default preferred version (V2). */\n  public ProtocolNegotiator() {\n    this(ProtocolVersion.getDefault());\n  }\n\n  /**\n   * Creates a negotiator with a specific preferred version.\n   *\n   * @param preferredVersion the protocol version to prefer when initiating connections\n   */\n  public ProtocolNegotiator(ProtocolVersion preferredVersion) {\n    this.preferredVersion = preferredVersion;\n  }\n\n  /**\n   * Negotiates the protocol version by detecting magic bytes from the input stream.\n   *\n   * <p>This method reads up to {@link #MAX_MAGIC_BYTES} bytes from the stream to detect the\n   * protocol version. The bytes are pushed back onto the stream (if using PushbackInputStream) or\n   * the stream is marked and reset.\n   *\n   * <p><b>IMPORTANT:</b> This method must be called ONCE per connection, before any other read\n   * operations. The stream must support either:\n   *\n   * <ul>\n   *   <li>PushbackInputStream with at least {@link #MAX_MAGIC_BYTES} bytes pushback buffer\n   *   <li>mark/reset with at least {@link #MAX_MAGIC_BYTES} read limit\n   * </ul>\n   *\n   * @param is the input stream to negotiate protocol on\n   * @return the detected ProtocolVersion (V2 if magic bytes match, V1 otherwise)\n   * @throws IOException if an I/O error occurs\n   * @throws IllegalArgumentException if the stream doesn't support pushback or mark/reset\n   */\n  public ProtocolVersion negotiate(InputStream is) throws IOException {\n    if (is instanceof PushbackInputStream) {\n      return negotiateWithPushback((PushbackInputStream) is);\n    } else if (is.markSupported()) {\n      return negotiateWithMark(is);\n    } else {\n      throw new IllegalArgumentException(\n          \"InputStream must be either PushbackInputStream or support mark/reset\");\n    }\n  }\n\n  /**\n   * Negotiates protocol version using PushbackInputStream.\n   *\n   * @param pis the pushback input stream\n   * @return the detected protocol version\n   * @throws IOException if an I/O error occurs\n   */\n  private ProtocolVersion negotiateWithPushback(PushbackInputStream pis) throws IOException {\n    byte[] prefix = new byte[MAX_MAGIC_BYTES];\n    int bytesRead = readFully(pis, prefix);\n\n    if (bytesRead < MAX_MAGIC_BYTES) {\n      throw new IOException(\"Connection closed during protocol negotiation\");\n    }\n\n    // Detect protocol version\n    ProtocolVersion detected = ProtocolVersion.detectFromPrefix(prefix);\n\n    // Push back the bytes we read\n    if (detected == ProtocolVersion.V2) {\n      // V2 magic bytes are consumed by the protocol, don't push back\n      // The V2 protocol expects to read these as part of its header\n    } else {\n      // V1 has no magic bytes, push everything back\n      pis.unread(prefix, 0, bytesRead);\n    }\n\n    return detected;\n  }\n\n  /**\n   * Negotiates protocol version using mark/reset.\n   *\n   * @param is the input stream supporting mark/reset\n   * @return the detected protocol version\n   * @throws IOException if an I/O error occurs\n   */\n  private ProtocolVersion negotiateWithMark(InputStream is) throws IOException {\n    is.mark(MAX_MAGIC_BYTES);\n\n    byte[] prefix = new byte[MAX_MAGIC_BYTES];\n    int bytesRead = readFully(is, prefix);\n\n    if (bytesRead < MAX_MAGIC_BYTES) {\n      throw new IOException(\"Connection closed during protocol negotiation\");\n    }\n\n    // Detect protocol version\n    ProtocolVersion detected = ProtocolVersion.detectFromPrefix(prefix);\n\n    // Reset stream to beginning\n    if (detected == ProtocolVersion.V2) {\n      // V2 magic bytes are part of the protocol, don't reset\n      // The stream is now positioned after the magic bytes\n    } else {\n      // V1 has no magic bytes, reset to beginning\n      is.reset();\n    }\n\n    return detected;\n  }\n\n  /**\n   * Negotiates protocol version on the agent side.\n   *\n   * <p>Reads the magic prefix sent by the client. If V2 is detected, responds with the same magic\n   * bytes. If V1 is detected, pushes the bytes back so Java serialization can read the header.\n   *\n   * @param input the input stream (must support pushback)\n   * @param output the output stream\n   * @return the negotiated ProtocolVersion\n   * @throws IOException if negotiation fails\n   */\n  public ProtocolVersion negotiateAgent(PushbackInputStream input, OutputStream output)\n      throws IOException {\n    ProtocolVersion detected = negotiateWithPushback(input);\n    if (detected == ProtocolVersion.V2) {\n      output.write(ProtocolVersion.V2.getMagicBytes());\n      output.flush();\n    }\n    return detected;\n  }\n\n  /**\n   * Negotiates protocol version on the client side.\n   *\n   * <p>If the preferred version is V2, sends the V2 magic bytes and waits for the agent response.\n   * Throws if the response does not match the V2 magic bytes.\n   *\n   * @param input the input stream\n   * @param output the output stream\n   * @param preferred the preferred protocol version\n   * @return the negotiated ProtocolVersion\n   * @throws IOException if negotiation fails\n   */\n  public ProtocolVersion negotiateClient(\n      InputStream input, OutputStream output, ProtocolVersion preferred) throws IOException {\n    if (preferred != ProtocolVersion.V2) {\n      return ProtocolVersion.V1;\n    }\n    byte[] magic = ProtocolVersion.V2.getMagicBytes();\n    output.write(magic);\n    output.flush();\n\n    byte[] response = new byte[magic.length];\n    int read = readFully(input, response);\n    if (read < magic.length) {\n      throw new IOException(\"Connection closed during protocol negotiation\");\n    }\n    if (!Arrays.equals(magic, response)) {\n      throw new IOException(\"Protocol negotiation failed: unexpected response\");\n    }\n    return ProtocolVersion.V2;\n  }\n\n  /**\n   * Returns the preferred protocol version for initiating connections.\n   *\n   * @return the preferred ProtocolVersion\n   */\n  public ProtocolVersion getPreferredVersion() {\n    return preferredVersion;\n  }\n\n  /**\n   * Creates a PushbackInputStream suitable for protocol negotiation.\n   *\n   * <p>The returned stream has a pushback buffer of {@link #MAX_MAGIC_BYTES} bytes, which is\n   * sufficient for detecting all protocol versions.\n   *\n   * @param is the underlying input stream\n   * @return a PushbackInputStream with appropriate buffer size\n   */\n  public static PushbackInputStream createNegotiationStream(InputStream is) {\n    if (is instanceof PushbackInputStream) {\n      return (PushbackInputStream) is;\n    }\n    return new PushbackInputStream(is, MAX_MAGIC_BYTES);\n  }\n\n  public static int getNegotiationTimeoutMs() {\n    String value = System.getProperty(PROP_NEGOTIATION_TIMEOUT);\n    if (value == null || value.trim().isEmpty()) {\n      return DEFAULT_NEGOTIATION_TIMEOUT_MS;\n    }\n    try {\n      return Integer.parseInt(value.trim());\n    } catch (NumberFormatException e) {\n      return DEFAULT_NEGOTIATION_TIMEOUT_MS;\n    }\n  }\n\n  private static int readFully(InputStream in, byte[] buffer) throws IOException {\n    int offset = 0;\n    while (offset < buffer.length) {\n      int read = in.read(buffer, offset, buffer.length - offset);\n      if (read < 0) {\n        break;\n      }\n      offset += read;\n    }\n    return offset;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/ProtocolVersion.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\n/**\n * Represents the wire protocol version for BTrace command communication.\n *\n * <p>BTrace supports multiple wire protocol versions to allow for performance improvements while\n * maintaining backward compatibility.\n */\npublic enum ProtocolVersion {\n  /**\n   * Version 1: Java ObjectInputStream/ObjectOutputStream serialization.\n   *\n   * <p>This is the original protocol using standard Java serialization. Compatible with all BTrace\n   * versions.\n   *\n   * <p>Characteristics:\n   *\n   * <ul>\n   *   <li>Uses ObjectOutputStream for serialization\n   *   <li>No magic byte prefix\n   *   <li>Larger payload sizes\n   *   <li>Slower serialization/deserialization\n   * </ul>\n   */\n  V1(1, new byte[] {}),\n\n  /**\n   * Version 2: Custom binary protocol with compression.\n   *\n   * <p>High-performance binary protocol with automatic compression for large payloads.\n   *\n   * <p>Characteristics:\n   *\n   * <ul>\n   *   <li>Magic byte prefix: 0x42 0x54 0x52 0x32 (\"BTR2\")\n   *   <li>3-6x faster serialization\n   *   <li>2-5x smaller payloads (10-100x with compression)\n   *   <li>Automatic deflate compression for payloads &gt; 1KB\n   *   <li>Zero-copy optimizations where possible\n   * </ul>\n   */\n  V2(2, new byte[] {0x42, 0x54, 0x52, 0x32}); // \"BTR2\"\n\n  private final int version;\n  private final byte[] magicBytes;\n\n  ProtocolVersion(int version, byte[] magicBytes) {\n    this.version = version;\n    this.magicBytes = magicBytes;\n  }\n\n  /**\n   * Returns the protocol version number.\n   *\n   * @return the version number (1 or 2)\n   */\n  public int getVersion() {\n    return version;\n  }\n\n  /**\n   * Returns the magic byte prefix for this protocol version.\n   *\n   * <p>V1 has no magic bytes (empty array). V2 uses \"BTR2\" (0x42 0x54 0x52 0x32).\n   *\n   * @return the magic byte prefix, or empty array if none\n   */\n  public byte[] getMagicBytes() {\n    return magicBytes.clone();\n  }\n\n  /**\n   * Returns whether this protocol version uses a magic byte prefix.\n   *\n   * @return true if this version has magic bytes, false otherwise\n   */\n  public boolean hasMagicBytes() {\n    return magicBytes.length > 0;\n  }\n\n  /**\n   * Looks up a protocol version by its version number.\n   *\n   * @param version the version number (1 or 2)\n   * @return the corresponding ProtocolVersion\n   * @throws IllegalArgumentException if the version number is not supported\n   */\n  public static ProtocolVersion fromVersion(int version) {\n    for (ProtocolVersion pv : values()) {\n      if (pv.version == version) {\n        return pv;\n      }\n    }\n    throw new IllegalArgumentException(\"Unsupported protocol version: \" + version);\n  }\n\n  /**\n   * Detects the protocol version from a magic byte prefix.\n   *\n   * <p>This method checks if the provided bytes match any known magic byte prefix. If no match is\n   * found, it assumes V1 (which has no magic bytes).\n   *\n   * @param prefix the first few bytes from the stream\n   * @return the detected ProtocolVersion (V2 if magic bytes match, V1 otherwise)\n   */\n  public static ProtocolVersion detectFromPrefix(byte[] prefix) {\n    if (prefix == null || prefix.length == 0) {\n      return V1;\n    }\n\n    // Check V2 magic bytes\n    if (prefix.length >= V2.magicBytes.length) {\n      boolean matches = true;\n      for (int i = 0; i < V2.magicBytes.length; i++) {\n        if (prefix[i] != V2.magicBytes[i]) {\n          matches = false;\n          break;\n        }\n      }\n      if (matches) {\n        return V2;\n      }\n    }\n\n    // Default to V1 if no magic bytes match\n    return V1;\n  }\n\n  /**\n   * Returns the default protocol version.\n   *\n   * <p>Currently defaults to V2 for new connections, but can be overridden via configuration.\n   *\n   * @return the default ProtocolVersion (V2)\n   */\n  public static ProtocolVersion getDefault() {\n    return V2;\n  }\n\n  @Override\n  public String toString() {\n    return \"ProtocolVersion{version=\" + version + \", hasMagicBytes=\" + hasMagicBytes() + \"}\";\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/ReconnectCommand.java",
    "content": "package org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\n\n/**\n * @since WireIO v.1\n */\npublic class ReconnectCommand extends Command {\n  public static final int STATUS_FLAG = 8;\n\n  private String probeId;\n\n  public ReconnectCommand() {\n    super(Command.RECONNECT);\n  }\n\n  public ReconnectCommand(String probeId) {\n    super(Command.RECONNECT);\n    this.probeId = probeId;\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeUTF(probeId);\n  }\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    probeId = in.readUTF();\n  }\n\n  public String getProbeId() {\n    return probeId;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/RenameCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\n\npublic class RenameCommand extends Command {\n  private String newName;\n\n  public RenameCommand(String newName) {\n    super(RENAME, true);\n    this.newName = newName;\n  }\n\n  protected RenameCommand() {\n    this(null);\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeUTF(newName);\n  }\n\n  @Override\n  protected void read(ObjectInput in) throws IOException {\n    newName = in.readUTF();\n  }\n\n  public String getNewName() {\n    return newName;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/RetransformClassNotification.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.io.PrintWriter;\n\n/**\n * This command is sent out as a notification that a class is going to be transformed\n *\n * @author Jaroslav Bachorik jaroslav.bachorik@sun.com\n */\npublic class RetransformClassNotification extends Command implements PrintableCommand {\n  private String className;\n\n  public RetransformClassNotification(String className) {\n    super(RETRANSFORM_CLASS, true);\n    this.className = className;\n  }\n\n  public RetransformClassNotification() {\n    super(RETRANSFORM_CLASS);\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeObject(className);\n  }\n\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    className = (String) in.readObject();\n  }\n\n  public String getClassName() {\n    return className;\n  }\n\n  @Override\n  public void print(PrintWriter out) {\n    out.append(\"Going to retransform class \").append(className).append('\\n');\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/RetransformationStartNotification.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.lang.instrument.Instrumentation;\n\n/**\n * This command is sent out when the BTrace engine calls {@linkplain\n * Instrumentation#retransformClasses(Class[])} method. It is followed by {@linkplain StatusCommand}\n * command when the retransformation ends.\n *\n * @author Jaroslav Bachorik jaroslav.bachorik@sun.com\n */\npublic class RetransformationStartNotification extends Command {\n  private int numClasses;\n\n  public RetransformationStartNotification() {\n    super(RETRANSFORMATION_START);\n  }\n\n  public RetransformationStartNotification(int numClasses) {\n    super(RETRANSFORMATION_START, true);\n    this.numClasses = numClasses;\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeInt(numClasses);\n  }\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    numClasses = in.readInt();\n  }\n\n  public int getNumClasses() {\n    return numClasses;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/SetSettingsCommand.java",
    "content": "/*\n * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * This command is used to remotely set custom settings (trusted mode, debug, etc.)\n *\n * @author Jaroslav Bachorik\n */\npublic class SetSettingsCommand extends Command {\n  private final Map<String, Object> params;\n\n  public SetSettingsCommand(Map<String, ?> params) {\n    super(SET_PARAMS, true);\n    this.params = params != null ? new HashMap<>(params) : new HashMap<>();\n  }\n\n  protected SetSettingsCommand() {\n    this(null);\n  }\n\n  public Map<String, Object> getParams() {\n    return params;\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeInt(params.size());\n    for (Map.Entry<String, ?> e : params.entrySet()) {\n      out.writeUTF(e.getKey());\n      out.writeObject(e.getValue());\n    }\n  }\n\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    int size = in.readInt();\n    if (size < 0 || size > 10000) { // Reasonable limit to prevent memory exhaustion\n      throw new IOException(\"Invalid params size: \" + size);\n    }\n    for (int i = 0; i < size; i++) {\n      String k = in.readUTF();\n      Object v = in.readObject();\n      // Validate that value is a reasonable settings type\n      if (v != null\n          && !(v instanceof String)\n          && !(v instanceof Number)\n          && !(v instanceof Boolean)) {\n        throw new IOException(\n            \"Invalid settings value type: expected String/Number/Boolean, got \"\n                + v.getClass().getName());\n      }\n      params.put(k, v);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/StatusCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\n\npublic class StatusCommand extends Command {\n  public static final int STATUS_FLAG = 1;\n  // custom flag\n  private int flag;\n\n  public StatusCommand(int flag) {\n    super(STATUS, true);\n    this.flag = flag;\n  }\n\n  public StatusCommand() {\n    this((byte) 0);\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeInt(flag);\n  }\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    flag = in.readInt();\n  }\n\n  public int getFlag() {\n    return Math.abs(flag);\n  }\n\n  public boolean isSuccess() {\n    return flag >= 0;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/StringMapDataCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.io.PrintWriter;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * A data command that hold data of type Map&lt;String, String&gt;.\n *\n * @author A. Sundararajan\n */\npublic class StringMapDataCommand extends DataCommand {\n\n  private Map<String, String> data;\n\n  public StringMapDataCommand() {\n    this(null, null);\n  }\n\n  public StringMapDataCommand(String name, Map<String, String> data) {\n    super(STRING_MAP, name, false);\n    if (data != null) {\n      this.data = new HashMap<>(data);\n    } else {\n      this.data = Collections.emptyMap();\n    }\n  }\n\n  public Map<String, String> getData() {\n    return data;\n  }\n\n  @Override\n  public void print(PrintWriter out) {\n    if (name != null && !name.isEmpty()) {\n      out.println(name);\n    }\n    for (Map.Entry<String, String> e : data.entrySet()) {\n      out.print(e.getKey());\n      out.print(\" = \");\n      out.println(e.getValue());\n    }\n  }\n\n  @Override\n  protected void write(ObjectOutput out) throws IOException {\n    out.writeUTF(name != null ? name : \"\");\n    out.writeInt(data.size());\n    for (String key : data.keySet()) {\n      out.writeUTF(key);\n      out.writeUTF(data.get(key));\n    }\n  }\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  protected void read(ObjectInput in) throws IOException, ClassNotFoundException {\n    name = in.readUTF();\n    data = new HashMap<>();\n    int sz = in.readInt();\n    for (int i = 0; i < sz; i++) {\n      data.put(in.readUTF(), in.readUTF());\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/WireIO.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\n\npublic class WireIO {\n  public static final int VERSION = 1;\n\n  private WireIO() {}\n\n  public static Command read(ObjectInput in) throws IOException {\n    byte type = in.readByte();\n    Command cmd;\n    switch (type) {\n      case Command.ERROR:\n        cmd = new ErrorCommand();\n        break;\n      case Command.EVENT:\n        cmd = new EventCommand();\n        break;\n      case Command.EXIT:\n        cmd = new ExitCommand();\n        break;\n      case Command.INSTRUMENT:\n        cmd = new InstrumentCommand();\n        break;\n      case Command.MESSAGE:\n        cmd = new MessageCommand();\n        break;\n      case Command.RENAME:\n        cmd = new RenameCommand();\n        break;\n      case Command.STATUS:\n        cmd = new StatusCommand();\n        break;\n      case Command.NUMBER_MAP:\n        cmd = new NumberMapDataCommand();\n        break;\n      case Command.STRING_MAP:\n        cmd = new StringMapDataCommand();\n        break;\n      case Command.NUMBER:\n        cmd = new NumberDataCommand();\n        break;\n      case Command.GRID_DATA:\n        cmd = new GridDataCommand();\n        break;\n      case Command.RETRANSFORMATION_START:\n        cmd = new RetransformationStartNotification();\n        break;\n      case Command.RETRANSFORM_CLASS:\n        cmd = new RetransformClassNotification();\n        break;\n      case Command.SET_PARAMS:\n        cmd = new SetSettingsCommand();\n        break;\n      case Command.LIST_PROBES:\n        cmd = new ListProbesCommand();\n        break;\n      case Command.DISCONNECT:\n        cmd = new DisconnectCommand();\n        break;\n      case Command.RECONNECT:\n        cmd = new ReconnectCommand();\n        break;\n      default:\n        throw new RuntimeException(\"invalid command: \" + type);\n    }\n    try {\n      cmd.read(in);\n    } catch (ClassNotFoundException cnfe) {\n      throw new IOException(cnfe);\n    }\n    return cmd;\n  }\n\n  @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n  public static void write(ObjectOutput out, Command cmd) throws IOException {\n    synchronized (out) {\n      out.writeByte(cmd.getType());\n      cmd.write(out);\n      if (cmd.isUrgent()) {\n        out.flush();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/WireProtocol.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.comm;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Abstract wire protocol for BTrace command communication.\n *\n * <p>This interface provides a pluggable abstraction for different wire protocol implementations,\n * allowing BTrace to support multiple serialization formats while maintaining a consistent API.\n *\n * <p>Implementations:\n *\n * <ul>\n *   <li>{@link JavaSerializationProtocol} - V1 protocol using ObjectInputStream/ObjectOutputStream\n *   <li>{@link BinaryWireProtocol} - V2 protocol using custom binary format\n * </ul>\n *\n * <p>Usage example:\n *\n * <pre>\n * // Create protocol based on negotiation\n * InputStream is = socket.getInputStream();\n * OutputStream os = socket.getOutputStream();\n *\n * ProtocolNegotiator negotiator = new ProtocolNegotiator();\n * ProtocolVersion version = negotiator.negotiate(createNegotiationStream(is));\n *\n * WireProtocol protocol = WireProtocol.create(version, is, os);\n *\n * // Read commands\n * Command cmd = protocol.read();\n *\n * // Write commands\n * protocol.write(new MessageCommand(\"hello\"));\n *\n * // Close when done\n * protocol.close();\n * </pre>\n */\npublic interface WireProtocol extends Closeable {\n\n  /**\n   * Reads a command from the input stream.\n   *\n   * <p>This method blocks until a complete command is available or an error occurs.\n   *\n   * @return the command read from the stream\n   * @throws IOException if an I/O error occurs or the stream is closed\n   * @throws ClassNotFoundException if the command type cannot be deserialized (V1 only)\n   */\n  Command read() throws IOException, ClassNotFoundException;\n\n  /**\n   * Writes a command to the output stream.\n   *\n   * <p>If the command is marked as urgent, the stream will be flushed immediately. Otherwise,\n   * buffering behavior depends on the underlying protocol implementation.\n   *\n   * @param command the command to write\n   * @throws IOException if an I/O error occurs or the stream is closed\n   */\n  void write(Command command) throws IOException;\n\n  /**\n   * Flushes any buffered data to the output stream.\n   *\n   * @throws IOException if an I/O error occurs\n   */\n  void flush() throws IOException;\n\n  /**\n   * Returns the protocol version in use.\n   *\n   * @return the ProtocolVersion\n   */\n  ProtocolVersion getVersion();\n\n  /**\n   * Closes the protocol and releases any associated resources.\n   *\n   * <p>After calling this method, no further read or write operations should be performed.\n   *\n   * @throws IOException if an I/O error occurs\n   */\n  @Override\n  void close() throws IOException;\n\n  /**\n   * Creates a WireProtocol instance for the specified version.\n   *\n   * <p>The streams should already be positioned correctly after protocol negotiation.\n   *\n   * @param version the protocol version to use\n   * @param inputStream the input stream to read commands from\n   * @param outputStream the output stream to write commands to\n   * @return a WireProtocol instance for the specified version\n   * @throws IOException if protocol initialization fails\n   */\n  static WireProtocol create(\n      ProtocolVersion version, InputStream inputStream, OutputStream outputStream)\n      throws IOException {\n    switch (version) {\n      case V1:\n        return new JavaSerializationProtocol(inputStream, outputStream);\n      case V2:\n        return new BinaryWireProtocol(inputStream, outputStream);\n      default:\n        throw new IllegalArgumentException(\"Unsupported protocol version: \" + version);\n    }\n  }\n\n  /**\n   * Creates a WireProtocol instance with automatic protocol negotiation.\n   *\n   * <p>This method performs protocol negotiation on the input stream and creates the appropriate\n   * WireProtocol implementation. The inputStream must support either PushbackInputStream or\n   * mark/reset.\n   *\n   * @param inputStream the input stream (will be wrapped in PushbackInputStream if needed)\n   * @param outputStream the output stream\n   * @return a WireProtocol instance for the negotiated version\n   * @throws IOException if negotiation or protocol initialization fails\n   */\n  static WireProtocol createWithNegotiation(InputStream inputStream, OutputStream outputStream)\n      throws IOException {\n    ProtocolNegotiator negotiator = new ProtocolNegotiator();\n    InputStream negotiationStream = ProtocolNegotiator.createNegotiationStream(inputStream);\n    ProtocolVersion version = negotiator.negotiate(negotiationStream);\n    return create(version, negotiationStream, outputStream);\n  }\n\n  /**\n   * Creates a WireProtocol instance with configuration-based setup.\n   *\n   * <p>If auto-negotiation is enabled in the config, performs negotiation. If forceVersion is set,\n   * uses the configured version without negotiation.\n   *\n   * @param config the protocol configuration\n   * @param inputStream the input stream\n   * @param outputStream the output stream\n   * @return a WireProtocol instance based on configuration\n   * @throws IOException if protocol setup fails\n   */\n  static WireProtocol createWithConfig(\n      ProtocolConfig config, InputStream inputStream, OutputStream outputStream)\n      throws IOException {\n    if (config.isForceVersion()) {\n      // Force specific version without negotiation\n      return create(config.getVersion(), inputStream, outputStream);\n    } else if (config.isAutoNegotiate()) {\n      // Perform negotiation\n      return createWithNegotiation(inputStream, outputStream);\n    } else {\n      // Use configured version without negotiation\n      return create(config.getVersion(), inputStream, outputStream);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryClient.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Map;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.CommandListener;\n\n/**\n * A client wrapper that uses the binary protocol for communication.\n * This provides a high-performance alternative to the standard Java serialization.\n */\npublic class BinaryClient {\n    private final InputStream inputStream;\n    private final OutputStream outputStream;\n    private final CommandListener commandListener;\n    private final ReentrantLock readLock = new ReentrantLock();\n    private final ReentrantLock writeLock = new ReentrantLock();\n    private volatile boolean closed = false;\n    \n    /**\n     * Create a new binary client with the specified streams and command listener\n     */\n    public BinaryClient(InputStream inputStream, OutputStream outputStream, CommandListener commandListener) {\n        this.inputStream = inputStream;\n        this.outputStream = outputStream;\n        this.commandListener = commandListener;\n    }\n    \n    /**\n     * Send an event command\n     */\n    public void sendEvent(String event) throws IOException {\n        send(new BinaryEventCommand(event));\n    }\n    \n    /**\n     * Send an exit command\n     */\n    public void sendExit(int exitCode) throws IOException {\n        send(new BinaryExitCommand(exitCode));\n    }\n    \n    /**\n     * Send an instrument command\n     */\n    public void sendInstrument(byte[] code, String[] args) throws IOException {\n        send(new BinaryInstrumentCommand(code, args));\n    }\n    \n    /**\n     * Send an instrument command\n     */\n    public void sendInstrument(byte[] code, Map<String, String> args) throws IOException {\n        send(new BinaryInstrumentCommand(code, args));\n    }\n    \n    /**\n     * Send a message command\n     */\n    public void sendMessage(String message, boolean urgent) throws IOException {\n        send(new BinaryMessageCommand(message, urgent));\n    }\n    \n    /**\n     * Send a binary command\n     */\n    public void send(BinaryCommand cmd) throws IOException {\n        if (closed) {\n            throw new IOException(\"Client is closed\");\n        }\n        \n        writeLock.lock();\n        try {\n            BinaryWireIO.write(outputStream, cmd);\n        } finally {\n            writeLock.unlock();\n        }\n    }\n    \n    /**\n     * Send an original BTrace command (will be converted to binary format)\n     */\n    public void send(Command cmd) throws IOException {\n        send(CommandAdapter.toBinaryCommand(cmd));\n    }\n    \n    /**\n     * Read and process commands in a loop\n     */\n    public void commandLoop() throws IOException {\n        if (closed) {\n            throw new IOException(\"Client is closed\");\n        }\n        \n        try {\n            while (!closed) {\n                BinaryCommand cmd = readCommand();\n                Command btraceCmd = CommandAdapter.toBtraceCommand(cmd);\n                commandListener.onCommand(btraceCmd);\n                \n                if (cmd.getType() == BinaryCommand.EXIT) {\n                    break;\n                }\n            }\n        } catch (IOException e) {\n            if (!closed) {\n                throw e;\n            }\n        }\n    }\n    \n    /**\n     * Read a single command from the input stream\n     */\n    public BinaryCommand readCommand() throws IOException {\n        if (closed) {\n            throw new IOException(\"Client is closed\");\n        }\n        \n        readLock.lock();\n        try {\n            return BinaryWireIO.read(inputStream);\n        } finally {\n            readLock.unlock();\n        }\n    }\n    \n    /**\n     * Close the client and all associated resources\n     */\n    public void close() throws IOException {\n        if (closed) {\n            return;\n        }\n        \n        closed = true;\n        \n        if (inputStream != null) {\n            inputStream.close();\n        }\n        \n        if (outputStream != null) {\n            outputStream.close();\n        }\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\n/**\n * Base class for all commands in the binary protocol.\n * This replaces the original Command class that relied on Java serialization.\n */\npublic abstract class BinaryCommand {\n    // Command types - must match the original Command class for compatibility\n    public static final byte ERROR = 0;\n    public static final byte EVENT = 1;\n    public static final byte EXIT = 2;\n    public static final byte INSTRUMENT = 3;\n    public static final byte MESSAGE = 4;\n    public static final byte RENAME = 5;\n    public static final byte STATUS = 6;\n    public static final byte NUMBER_MAP = 7;\n    public static final byte STRING_MAP = 8;\n    public static final byte NUMBER = 9;\n    public static final byte GRID_DATA = 10;\n    public static final byte RETRANSFORMATION_START = 11;\n    public static final byte RETRANSFORM_CLASS = 12;\n    public static final byte SET_PARAMS = 13;\n    public static final byte LIST_PROBES = 14;\n    public static final byte DISCONNECT = 15;\n    public static final byte RECONNECT = 16;\n    public static final byte LIST_FAILED_EXTENSIONS = 17;\n\n    public static final byte FIRST_COMMAND = ERROR;\n    public static final byte LAST_COMMAND = LIST_FAILED_EXTENSIONS;\n\n    // Used for command registration and creation\n    private static final Map<Byte, Supplier<BinaryCommand>> COMMAND_FACTORIES = new HashMap<>();\n\n    // Register command factories\n    static {\n        registerCommand(ERROR, BinaryErrorCommand::new);\n        registerCommand(EVENT, BinaryEventCommand::new);\n        registerCommand(EXIT, BinaryExitCommand::new);\n        registerCommand(INSTRUMENT, BinaryInstrumentCommand::new);\n        registerCommand(MESSAGE, BinaryMessageCommand::new);\n        registerCommand(RENAME, BinaryRenameCommand::new);\n        registerCommand(STATUS, BinaryStatusCommand::new);\n        registerCommand(NUMBER_MAP, BinaryNumberMapDataCommand::new);\n        registerCommand(STRING_MAP, BinaryStringMapDataCommand::new);\n        registerCommand(NUMBER, BinaryNumberDataCommand::new);\n        registerCommand(GRID_DATA, BinaryGridDataCommand::new);\n        registerCommand(RETRANSFORMATION_START, BinaryRetransformationStartNotification::new);\n        registerCommand(RETRANSFORM_CLASS, BinaryRetransformClassNotification::new);\n        registerCommand(SET_PARAMS, BinarySetSettingsCommand::new);\n        registerCommand(LIST_PROBES, BinaryListProbesCommand::new);\n        registerCommand(DISCONNECT, BinaryDisconnectCommand::new);\n        registerCommand(RECONNECT, BinaryReconnectCommand::new);\n        registerCommand(LIST_FAILED_EXTENSIONS, BinaryListFailedExtensionsCommand::new);\n    }\n\n    /**\n     * Register a command factory for a specific command type\n     */\n    public static void registerCommand(byte type, Supplier<BinaryCommand> factory) {\n        COMMAND_FACTORIES.put(type, factory);\n    }\n\n    /**\n     * Create a command instance for the given type\n     */\n    public static BinaryCommand createCommand(byte type) {\n        Supplier<BinaryCommand> factory = COMMAND_FACTORIES.get(type);\n        if (factory == null) {\n            throw new IllegalArgumentException(\"Unknown command type: \" + type);\n        }\n        return factory.get();\n    }\n\n    protected byte type;\n    private boolean urgent;\n\n    protected BinaryCommand(byte type) {\n        this(type, true);\n    }\n\n    protected BinaryCommand(byte type, boolean urgent) {\n        if (type < FIRST_COMMAND || type > LAST_COMMAND) {\n            throw new IllegalArgumentException(\"Invalid command type: \" + type);\n        }\n        this.type = type;\n        this.urgent = urgent;\n    }\n\n    /**\n     * Write this command to the output stream\n     */\n    protected abstract void write(OutputStream out) throws IOException;\n\n    /**\n     * Read this command from the input stream\n     */\n    protected abstract void read(InputStream in) throws IOException;\n\n    /**\n     * Get the type of this command\n     */\n    public final byte getType() {\n        return type;\n    }\n\n    /**\n     * Check if this command needs urgent processing\n     */\n    public final boolean isUrgent() {\n        return urgent;\n    }\n\n    /**\n     * Set this command as urgent\n     */\n    final void setUrgent() {\n        urgent = true;\n    }\n} \n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryDataCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Abstract base class for data commands.\n * These commands are used to send monitoring data from the BTrace agent to the client.\n */\npublic abstract class BinaryDataCommand extends BinaryCommand {\n    protected String name;\n\n    protected BinaryDataCommand(byte type, String name) {\n        super(type, false);\n        this.name = name;\n    }\n\n    protected BinaryDataCommand(byte type) {\n        this(type, null);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        BinaryProtocol.writeString(out, name);\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        name = BinaryProtocol.readString(in);\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryDisconnectCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\n/**\n * Binary implementation of the DisconnectCommand.\n * This command is used to disconnect a BTrace client without stopping the agent.\n */\npublic class BinaryDisconnectCommand extends BinaryStringCommand {\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(DISCONNECT, BinaryDisconnectCommand::new);\n    }\n\n    public BinaryDisconnectCommand(String probeId) {\n        super(DISCONNECT, probeId);\n    }\n\n    public BinaryDisconnectCommand() {\n        this(\"\");\n    }\n\n    public String getProbeId() {\n        return getPayload();\n    }\n\n    public void setProbeId(String probeId) {\n        setPayload(probeId);\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryErrorCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Binary implementation of the ErrorCommand.\n * This command is used to send error information from the BTrace agent to the client.\n */\npublic class BinaryErrorCommand extends BinaryCommand {\n    private String exceptionClass;\n    private String message;\n    private String stackTrace;\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(ERROR, BinaryErrorCommand::new);\n    }\n\n    public BinaryErrorCommand(String exceptionClass, String message, String stackTrace) {\n        super(ERROR, true);\n        this.exceptionClass = exceptionClass;\n        this.message = message;\n        this.stackTrace = stackTrace;\n    }\n\n    public BinaryErrorCommand() {\n        this(null, null, null);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        BinaryProtocol.writeString(out, exceptionClass);\n        BinaryProtocol.writeString(out, message);\n        BinaryProtocol.writeString(out, stackTrace);\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        exceptionClass = BinaryProtocol.readString(in);\n        message = BinaryProtocol.readString(in);\n        stackTrace = BinaryProtocol.readString(in);\n    }\n\n    public String getExceptionClass() {\n        return exceptionClass;\n    }\n\n    public void setExceptionClass(String exceptionClass) {\n        this.exceptionClass = exceptionClass;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public String getStackTrace() {\n        return stackTrace;\n    }\n\n    public void setStackTrace(String stackTrace) {\n        this.stackTrace = stackTrace;\n    }\n} \n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryEventCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\n/**\n * Binary implementation of the EventCommand.\n * This command is used to send events to BTrace agents.\n */\npublic class BinaryEventCommand extends BinaryStringCommand {\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(EVENT, BinaryEventCommand::new);\n    }\n\n    public BinaryEventCommand(String event) {\n        super(EVENT, event);\n    }\n\n    public BinaryEventCommand() {\n        this(null);\n    }\n\n    public String getEvent() {\n        return getPayload();\n    }\n\n    public void setEvent(String event) {\n        setPayload(event);\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryExitCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Binary implementation of the ExitCommand.\n * This command is used to signal the BTrace agent to exit.\n */\npublic class BinaryExitCommand extends BinaryCommand {\n    private int exitCode;\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(EXIT, BinaryExitCommand::new);\n    }\n\n    public BinaryExitCommand(int exitCode) {\n        super(EXIT, true);\n        this.exitCode = exitCode;\n    }\n\n    public BinaryExitCommand() {\n        this(0);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        BinaryProtocol.writeInt(out, exitCode);\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        exitCode = BinaryProtocol.readInt(in);\n    }\n\n    public int getExitCode() {\n        return exitCode;\n    }\n\n    public void setExitCode(int exitCode) {\n        this.exitCode = exitCode;\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryGridDataCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Binary implementation of the GridDataCommand.\n * This command is used to send tabular data from the BTrace agent to the client.\n */\npublic class BinaryGridDataCommand extends BinaryDataCommand {\n    private List<String> columnNames = new ArrayList<>();\n    private List<Object[]> data = new ArrayList<>();\n    private static final ScalarEncoding SCALAR =\n        new ScalarEncoding((byte)0, (byte)1, (byte)2, (byte)3, (byte)4, (byte)5, (byte)6);\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(GRID_DATA, BinaryGridDataCommand::new);\n    }\n\n    public BinaryGridDataCommand(String name, List<String> columnNames, List<Object[]> data) {\n        super(GRID_DATA, name);\n        if (columnNames != null) {\n            this.columnNames.addAll(columnNames);\n        }\n        if (data != null) {\n            this.data.addAll(data);\n        }\n    }\n\n    public BinaryGridDataCommand() {\n        this(null, null, null);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        // Write the name\n        super.write(out);\n        \n        // Write the column names\n        BinaryProtocol.writeInt(out, columnNames.size());\n        for (String columnName : columnNames) {\n            BinaryProtocol.writeString(out, columnName);\n        }\n        \n        // Write the data\n        BinaryProtocol.writeInt(out, data.size());\n        for (Object[] row : data) {\n            // Write the row length\n            int rowLength = row != null ? row.length : 0;\n            BinaryProtocol.writeInt(out, rowLength);\n            \n            // Write each cell\n            if (row != null) {\n                for (Object cell : row) {\n                    SCALAR.writeValue(out, cell);\n                }\n            }\n        }\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        // Read the name\n        super.read(in);\n        \n        // Read the column names\n        int columnCount = BinaryProtocol.readInt(in);\n        columnNames.clear();\n        for (int i = 0; i < columnCount; i++) {\n            columnNames.add(BinaryProtocol.readString(in));\n        }\n        \n        // Read the data\n        int rowCount = BinaryProtocol.readInt(in);\n        data.clear();\n        for (int i = 0; i < rowCount; i++) {\n            // Read the row length\n            int rowLength = BinaryProtocol.readInt(in);\n            \n            // Read each cell\n            Object[] row = new Object[rowLength];\n            for (int j = 0; j < rowLength; j++) {\n                row[j] = SCALAR.readValue(in);\n            }\n            \n            data.add(row);\n        }\n    }\n\n    public List<String> getColumnNames() {\n        return new ArrayList<>(columnNames);\n    }\n\n    public void setColumnNames(List<String> columnNames) {\n        this.columnNames.clear();\n        if (columnNames != null) {\n            this.columnNames.addAll(columnNames);\n        }\n    }\n\n    public List<Object[]> getData() {\n        List<Object[]> result = new ArrayList<>(data.size());\n        for (Object[] row : data) {\n            result.add(row.clone());\n        }\n        return result;\n    }\n\n    public void setData(List<Object[]> data) {\n        this.data.clear();\n        if (data != null) {\n            for (Object[] row : data) {\n                this.data.add(row.clone());\n            }\n        }\n    }\n\n    public void addRow(Object[] row) {\n        if (row != null) {\n            this.data.add(row.clone());\n        }\n    }\n} \n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryInstrumentCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Map;\n\nimport org.openjdk.btrace.core.ArgsMap;\n\n/**\n * Binary implementation of the InstrumentCommand.\n * This command is used to send BTrace code to the target VM for instrumentation.\n */\npublic class BinaryInstrumentCommand extends BinaryCommand {\n    private byte[] code;\n    private ArgsMap args;\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(INSTRUMENT, BinaryInstrumentCommand::new);\n    }\n\n    public BinaryInstrumentCommand(byte[] code, ArgsMap args) {\n        super(INSTRUMENT, true);\n        this.code = code;\n        this.args = args;\n    }\n\n    public BinaryInstrumentCommand(byte[] code, String[] args) {\n        this(code, new ArgsMap(args));\n    }\n\n    public BinaryInstrumentCommand(byte[] code, Map<String, String> args) {\n        this(code, new ArgsMap(args));\n    }\n\n    public BinaryInstrumentCommand() {\n        this(null, (Map<String, String>) null);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        // Write code bytes\n        BinaryProtocol.writeByteArray(out, code);\n        \n        // Write args count\n        BinaryProtocol.writeInt(out, args.size());\n        \n        // Write args\n        for (Map.Entry<String, String> e : args) {\n            BinaryProtocol.writeString(out, e.getKey());\n            BinaryProtocol.writeString(out, e.getValue() != null ? e.getValue() : \"\");\n        }\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        // Read code bytes\n        code = BinaryProtocol.readByteArray(in);\n        \n        // Read args count\n        int argsCount = BinaryProtocol.readInt(in);\n        \n        // Read args\n        args = new ArgsMap(argsCount);\n        for (int i = 0; i < argsCount; i++) {\n            String key = BinaryProtocol.readString(in);\n            String val = BinaryProtocol.readString(in);\n            args.put(key, val);\n        }\n    }\n\n    public byte[] getCode() {\n        return code;\n    }\n\n    public ArgsMap getArguments() {\n        return args;\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryListFailedExtensionsCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * Binary implementation of the ListFailedExtensionsCommand.\n * This command is used to list extensions that failed to load.\n */\npublic class BinaryListFailedExtensionsCommand extends BinaryCommand {\n    private final List<String> failures = new ArrayList<>();\n\n    static {\n        BinaryCommand.registerCommand(LIST_FAILED_EXTENSIONS, BinaryListFailedExtensionsCommand::new);\n    }\n\n    public BinaryListFailedExtensionsCommand() {\n        super(LIST_FAILED_EXTENSIONS, true);\n    }\n\n    public void setFailures(Collection<String> failures) {\n        this.failures.clear();\n        if (failures != null) {\n            this.failures.addAll(failures);\n        }\n    }\n\n    public List<String> getFailures() {\n        return new ArrayList<>(failures);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        BinaryProtocol.writeInt(out, failures.size());\n        for (String failure : failures) {\n            BinaryProtocol.writeString(out, failure);\n        }\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        int count = BinaryProtocol.readInt(in);\n        failures.clear();\n        for (int i = 0; i < count; i++) {\n            failures.add(BinaryProtocol.readString(in));\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryListProbesCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * Binary implementation of the ListProbesCommand.\n * This command is used to list active BTrace probes.\n */\npublic class BinaryListProbesCommand extends BinaryCommand {\n    private final List<String> probes = new ArrayList<>();\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(LIST_PROBES, BinaryListProbesCommand::new);\n    }\n\n    public BinaryListProbesCommand() {\n        super(LIST_PROBES, true);\n    }\n\n    public void setProbes(Collection<String> probes) {\n        this.probes.clear();\n        this.probes.addAll(probes);\n    }\n\n    public List<String> getProbes() {\n        return new ArrayList<>(probes);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        BinaryProtocol.writeInt(out, probes.size());\n        for (String probe : probes) {\n            BinaryProtocol.writeString(out, probe);\n        }\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        int numProbes = BinaryProtocol.readInt(in);\n        probes.clear();\n        for (int i = 0; i < numProbes; i++) {\n            probes.add(BinaryProtocol.readString(in));\n        }\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryMessageCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.zip.Deflater;\nimport java.util.zip.DeflaterOutputStream;\nimport java.util.zip.Inflater;\nimport java.util.zip.InflaterInputStream;\n\n/**\n * Binary implementation of the MessageCommand with compression support.\n * This command is used to send messages from the BTrace agent to the client.\n */\npublic class BinaryMessageCommand extends BinaryCommand {\n    // Compression threshold in bytes\n    private static final int COMPRESSION_THRESHOLD = 1024;\n    \n    // Message content\n    private String message;\n    private boolean urgent;\n    private long timestamp;\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(MESSAGE, BinaryMessageCommand::new);\n    }\n\n    public BinaryMessageCommand(long timestamp, String message, boolean urgent) {\n        super(MESSAGE, urgent);\n        this.message = message;\n        this.urgent = urgent;\n        this.timestamp = timestamp;\n    }\n\n    public BinaryMessageCommand(String message, boolean urgent) {\n        this(System.currentTimeMillis(), message, urgent);\n    }\n\n    public BinaryMessageCommand(String message) {\n        this(System.currentTimeMillis(), message, false);\n    }\n\n    public BinaryMessageCommand() {\n        this(null);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        // Write timestamp\n        BinaryProtocol.writeLong(out, timestamp);\n        \n        // Write urgent flag\n        BinaryProtocol.writeBoolean(out, urgent);\n        \n        // Convert message to bytes\n        byte[] messageBytes = message != null \n            ? message.getBytes(StandardCharsets.UTF_8) \n            : new byte[0];\n        \n        // Determine if compression should be used\n        boolean compress = messageBytes.length > COMPRESSION_THRESHOLD;\n        BinaryProtocol.writeBoolean(out, compress);\n        \n        if (compress) {\n            // Compress the message\n            ByteArrayOutputStream compressedBytes = new ByteArrayOutputStream();\n            DeflaterOutputStream deflaterStream = new DeflaterOutputStream(\n                compressedBytes, \n                new Deflater(Deflater.BEST_SPEED)\n            );\n            \n            deflaterStream.write(messageBytes);\n            deflaterStream.finish();\n            deflaterStream.close();\n            \n            // Write the compressed bytes\n            byte[] compressedData = compressedBytes.toByteArray();\n            BinaryProtocol.writeInt(out, messageBytes.length); // Original size\n            BinaryProtocol.writeInt(out, compressedData.length); // Compressed size\n            out.write(compressedData);\n        } else {\n            // Write uncompressed message\n            BinaryProtocol.writeInt(out, messageBytes.length);\n            if (messageBytes.length > 0) {\n                out.write(messageBytes);\n            }\n        }\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        // Read timestamp\n        timestamp = BinaryProtocol.readLong(in);\n\n        // Read urgent flag\n        urgent = BinaryProtocol.readBoolean(in);\n        if (urgent) {\n            setUrgent();\n        }\n        \n        // Check if the message is compressed\n        boolean compressed = BinaryProtocol.readBoolean(in);\n        \n        if (compressed) {\n            // Read the original and compressed sizes\n            int originalSize = BinaryProtocol.readInt(in);\n            int compressedSize = BinaryProtocol.readInt(in);\n            \n            // Read and decompress the message\n            byte[] compressedData = new byte[compressedSize];\n            BinaryProtocol.readFully(in, compressedData);\n            \n            // Create an inflater to decompress\n            InflaterInputStream inflaterStream = new InflaterInputStream(\n                new ByteArrayInputStream(compressedData),\n                new Inflater()\n            );\n            \n            // Read the decompressed data\n            byte[] decompressedData = new byte[originalSize];\n            BinaryProtocol.readFully(inflaterStream, decompressedData);\n            \n            // Convert to string\n            message = new String(decompressedData, StandardCharsets.UTF_8);\n        } else {\n            // Read uncompressed message\n            int length = BinaryProtocol.readInt(in);\n            if (length > 0) {\n                byte[] messageBytes = new byte[length];\n                BinaryProtocol.readFully(in, messageBytes);\n                message = new String(messageBytes, StandardCharsets.UTF_8);\n            } else {\n                message = \"\";\n            }\n        }\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n} \n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryNumberDataCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Binary implementation of the NumberDataCommand.\n * This command is used to send numeric data from the BTrace agent to the client.\n */\npublic class BinaryNumberDataCommand extends BinaryDataCommand {\n    private Number value;\n    private static final NumberEncoding ENCODING =\n        new NumberEncoding(\n            (byte)0, (byte)1, (byte)2, (byte)3, (byte)4, (byte)5, (byte)6);\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(NUMBER, BinaryNumberDataCommand::new);\n    }\n\n    public BinaryNumberDataCommand(String name, Number value) {\n        super(NUMBER, name);\n        this.value = value;\n    }\n\n    public BinaryNumberDataCommand() {\n        this(null, null);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        // Write the name\n        super.write(out);\n        \n        // Write the value type + payload via unified encoding\n        ENCODING.writeNumber(out, value);\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        // Read the name\n        super.read(in);\n        \n        // Read the value via unified encoding\n        value = ENCODING.readNumber(in);\n    }\n\n    public Number getValue() {\n        return value;\n    }\n\n    public void setValue(Number value) {\n        this.value = value;\n    }\n} \n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryNumberMapDataCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * Binary implementation of the NumberMapDataCommand.\n * This command is used to send numeric map data from the BTrace agent to the client.\n */\npublic class BinaryNumberMapDataCommand extends BinaryDataCommand {\n    private Map<String, Number> data = new LinkedHashMap<>();\n    private static final NumberEncoding ENCODING =\n        new NumberEncoding(\n            (byte)0, (byte)1, (byte)2, (byte)3, (byte)4, (byte)5, (byte)6);\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(NUMBER_MAP, BinaryNumberMapDataCommand::new);\n    }\n\n    public BinaryNumberMapDataCommand(String name, Map<String, Number> data) {\n        super(NUMBER_MAP, name);\n        if (data != null) {\n            this.data.putAll(data);\n        }\n    }\n\n    public BinaryNumberMapDataCommand() {\n        this(null, null);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        // Write the name\n        super.write(out);\n        \n        // Write the map size\n        BinaryProtocol.writeInt(out, data.size());\n        \n        // Write each map entry\n        for (Map.Entry<String, Number> entry : data.entrySet()) {\n            BinaryProtocol.writeString(out, entry.getKey());\n            ENCODING.writeNumber(out, entry.getValue());\n        }\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        // Read the name\n        super.read(in);\n        \n        // Read the map size\n        int size = BinaryProtocol.readInt(in);\n        \n        // Clear any existing data\n        data.clear();\n        \n        // Read each map entry\n        for (int i = 0; i < size; i++) {\n            String key = BinaryProtocol.readString(in);\n            \n            Number value = ENCODING.readNumber(in);\n            data.put(key, value);\n        }\n    }\n\n    public Map<String, Number> getData() {\n        return new LinkedHashMap<>(data);\n    }\n\n    public void setData(Map<String, Number> data) {\n        this.data.clear();\n        if (data != null) {\n            this.data.putAll(data);\n        }\n    }\n} \n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryProtocol.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.StandardCharsets;\n\n/**\n * A utility class for binary serialization and deserialization.\n * This replaces the default Java serialization with a more efficient binary protocol.\n */\npublic class BinaryProtocol {\n    public static final byte VERSION = 3;\n\n    // Maximum size for strings and byte arrays to prevent OOM attacks (100MB)\n    private static final int MAX_ALLOCATION_SIZE = 100 * 1024 * 1024;\n\n    // Basic read functions\n    \n    public static byte readByte(InputStream is) throws IOException {\n        int value = is.read();\n        if (value == -1) {\n            throw new IOException(\"End of stream reached\");\n        }\n        return (byte) value;\n    }\n    \n    public static int readInt(InputStream is) throws IOException {\n        byte[] buffer = new byte[4];\n        readFully(is, buffer);\n        return ByteBuffer.wrap(buffer).getInt();\n    }\n    \n    public static long readLong(InputStream is) throws IOException {\n        byte[] buffer = new byte[8];\n        readFully(is, buffer);\n        return ByteBuffer.wrap(buffer).getLong();\n    }\n    \n    public static float readFloat(InputStream is) throws IOException {\n        byte[] buffer = new byte[4];\n        readFully(is, buffer);\n        return ByteBuffer.wrap(buffer).getFloat();\n    }\n    \n    public static double readDouble(InputStream is) throws IOException {\n        byte[] buffer = new byte[8];\n        readFully(is, buffer);\n        return ByteBuffer.wrap(buffer).getDouble();\n    }\n    \n    public static boolean readBoolean(InputStream is) throws IOException {\n        return readByte(is) != 0;\n    }\n    \n    public static String readString(InputStream is) throws IOException {\n        int length = readInt(is);\n        if (length == -1) {\n            return null;\n        }\n        if (length == 0) {\n            return \"\";\n        }\n        if (length < 0 || length > MAX_ALLOCATION_SIZE) {\n            throw new IOException(\"Invalid string length: \" + length +\n                \" (must be between 0 and \" + MAX_ALLOCATION_SIZE + \")\");\n        }\n        byte[] buffer = new byte[length];\n        readFully(is, buffer);\n        return new String(buffer, StandardCharsets.UTF_8);\n    }\n    \n    public static byte[] readByteArray(InputStream is) throws IOException {\n        int length = readInt(is);\n        if (length == -1) {\n            return null;\n        }\n        if (length == 0) {\n            return new byte[0];\n        }\n        if (length < 0 || length > MAX_ALLOCATION_SIZE) {\n            throw new IOException(\"Invalid byte array length: \" + length +\n                \" (must be between 0 and \" + MAX_ALLOCATION_SIZE + \")\");\n        }\n        byte[] buffer = new byte[length];\n        readFully(is, buffer);\n        return buffer;\n    }\n    \n    // Basic write functions\n    \n    public static void writeByte(OutputStream os, byte value) throws IOException {\n        os.write(value);\n    }\n    \n    public static void writeInt(OutputStream os, int value) throws IOException {\n        ByteBuffer buffer = ByteBuffer.allocate(4);\n        buffer.putInt(value);\n        os.write(buffer.array());\n    }\n    \n    public static void writeLong(OutputStream os, long value) throws IOException {\n        ByteBuffer buffer = ByteBuffer.allocate(8);\n        buffer.putLong(value);\n        os.write(buffer.array());\n    }\n    \n    public static void writeFloat(OutputStream os, float value) throws IOException {\n        ByteBuffer buffer = ByteBuffer.allocate(4);\n        buffer.putFloat(value);\n        os.write(buffer.array());\n    }\n    \n    public static void writeDouble(OutputStream os, double value) throws IOException {\n        ByteBuffer buffer = ByteBuffer.allocate(8);\n        buffer.putDouble(value);\n        os.write(buffer.array());\n    }\n    \n    public static void writeBoolean(OutputStream os, boolean value) throws IOException {\n        writeByte(os, value ? (byte) 1 : (byte) 0);\n    }\n    \n    public static void writeString(OutputStream os, String value) throws IOException {\n        if (value == null) {\n            writeInt(os, -1);\n            return;\n        }\n        byte[] bytes = value.getBytes(StandardCharsets.UTF_8);\n        writeInt(os, bytes.length);\n        if (bytes.length > 0) {\n            os.write(bytes);\n        }\n    }\n    \n    public static void writeByteArray(OutputStream os, byte[] value) throws IOException {\n        if (value == null) {\n            writeInt(os, -1);\n            return;\n        }\n        writeInt(os, value.length);\n        if (value.length > 0) {\n            os.write(value);\n        }\n    }\n    \n    // Utility functions\n    \n    public static void readFully(InputStream is, byte[] buffer) throws IOException {\n        readFully(is, buffer, 0, buffer.length);\n    }\n    \n    public static void readFully(InputStream is, byte[] buffer, int offset, int length) throws IOException {\n        int totalBytesRead = 0;\n        while (totalBytesRead < length) {\n            int bytesRead = is.read(buffer, offset + totalBytesRead, length - totalBytesRead);\n            if (bytesRead == -1) {\n                throw new IOException(\"End of stream reached\");\n            }\n            totalBytesRead += bytesRead;\n        }\n    }\n} \n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryReconnectCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\n/**\n * Binary implementation of the ReconnectCommand.\n * This command is used to reconnect to a running BTrace agent.\n */\npublic class BinaryReconnectCommand extends BinaryStringCommand {\n    public static final int STATUS_FLAG = 8;\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(RECONNECT, BinaryReconnectCommand::new);\n    }\n\n    public BinaryReconnectCommand(String probeId) {\n        super(RECONNECT, probeId);\n    }\n\n    public BinaryReconnectCommand() {\n        this(null);\n    }\n\n    public String getProbeId() {\n        return getPayload();\n    }\n\n    public void setProbeId(String probeId) {\n        setPayload(probeId);\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryRenameCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\n/**\n * Binary implementation of the RenameCommand.\n * This command is used to rename BTrace output files.\n */\npublic class BinaryRenameCommand extends BinaryStringCommand {\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(RENAME, BinaryRenameCommand::new);\n    }\n\n    public BinaryRenameCommand(String newName) {\n        super(RENAME, newName);\n    }\n\n    public BinaryRenameCommand() {\n        this(null);\n    }\n\n    public String getNewName() {\n        return getPayload();\n    }\n\n    public void setNewName(String newName) {\n        setPayload(newName);\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryRetransformClassNotification.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Binary implementation of the RetransformClassNotification.\n * This command is used to notify the client about a class that's being retransformed.\n */\npublic class BinaryRetransformClassNotification extends BinaryCommand {\n    private String className;\n    private int index;\n    private int total;\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(RETRANSFORM_CLASS, BinaryRetransformClassNotification::new);\n    }\n\n    public BinaryRetransformClassNotification(String className, int index, int total) {\n        super(RETRANSFORM_CLASS, true);\n        this.className = className;\n        this.index = index;\n        this.total = total;\n    }\n\n    public BinaryRetransformClassNotification() {\n        this(null, 0, 0);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        BinaryProtocol.writeString(out, className);\n        BinaryProtocol.writeInt(out, index);\n        BinaryProtocol.writeInt(out, total);\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        className = BinaryProtocol.readString(in);\n        index = BinaryProtocol.readInt(in);\n        total = BinaryProtocol.readInt(in);\n    }\n\n    public String getClassName() {\n        return className;\n    }\n\n    public void setClassName(String className) {\n        this.className = className;\n    }\n\n    public int getIndex() {\n        return index;\n    }\n\n    public void setIndex(int index) {\n        this.index = index;\n    }\n\n    public int getTotal() {\n        return total;\n    }\n\n    public void setTotal(int total) {\n        this.total = total;\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryRetransformationStartNotification.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Binary implementation of the RetransformationStartNotification.\n * This command is used to notify the client that class retransformation is about to start.\n */\npublic class BinaryRetransformationStartNotification extends BinaryCommand {\n    private int numClasses;\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(RETRANSFORMATION_START, BinaryRetransformationStartNotification::new);\n    }\n\n    public BinaryRetransformationStartNotification(int numClasses) {\n        super(RETRANSFORMATION_START, true);\n        this.numClasses = numClasses;\n    }\n\n    public BinaryRetransformationStartNotification() {\n        this(0);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        BinaryProtocol.writeInt(out, numClasses);\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        numClasses = BinaryProtocol.readInt(in);\n    }\n\n    public int getNumClasses() {\n        return numClasses;\n    }\n\n    public void setNumClasses(int numClasses) {\n        this.numClasses = numClasses;\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinarySetSettingsCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Binary implementation of the SetSettingsCommand.\n * This command is used to configure the BTrace agent settings.\n */\npublic class BinarySetSettingsCommand extends BinaryCommand {\n    // Supported parameter types and their type codes\n    private static final byte TYPE_STRING = 1;\n    private static final byte TYPE_INTEGER = 2;\n    private static final byte TYPE_LONG = 3;\n    private static final byte TYPE_BOOLEAN = 4;\n    private static final byte TYPE_FLOAT = 5;\n    private static final byte TYPE_DOUBLE = 6;\n\n    private final Map<String, Object> params;\n    private static final ScalarEncoding SCALAR =\n        new ScalarEncoding(\n            (byte)0,\n            TYPE_STRING,\n            TYPE_INTEGER,\n            TYPE_LONG,\n            TYPE_FLOAT,\n            TYPE_DOUBLE,\n            TYPE_BOOLEAN);\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(SET_PARAMS, BinarySetSettingsCommand::new);\n    }\n\n    public BinarySetSettingsCommand(Map<String, ?> params) {\n        super(SET_PARAMS, true);\n        this.params = params != null ? new HashMap<>(params) : new HashMap<>();\n    }\n\n    public BinarySetSettingsCommand() {\n        this(null);\n    }\n\n    public Map<String, Object> getParams() {\n        return new HashMap<>(params);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        // Write the number of parameters\n        BinaryProtocol.writeInt(out, params.size());\n        \n        // Write each parameter\n        for (Map.Entry<String, ?> entry : params.entrySet()) {\n            BinaryProtocol.writeString(out, entry.getKey());\n            SCALAR.writeValue(out, entry.getValue());\n        }\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        // Read the number of parameters\n        int size = BinaryProtocol.readInt(in);\n        \n        // Clear any existing parameters\n        params.clear();\n        \n        // Read each parameter\n        for (int i = 0; i < size; i++) {\n            // Read the parameter key\n            String key = BinaryProtocol.readString(in);\n            \n            Object value = SCALAR.readValue(in);\n            \n            // Store the parameter\n            params.put(key, value);\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryStatusCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Binary implementation of the StatusCommand.\n * This command is used to communicate the status of BTrace operations.\n */\npublic class BinaryStatusCommand extends BinaryCommand {\n    // Status flag constants\n    public static final int STATUS_FLAG = 1;\n    \n    private int flag;\n    private boolean success;\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(STATUS, BinaryStatusCommand::new);\n    }\n\n    public BinaryStatusCommand(int flag) {\n        this(flag, true);\n    }\n\n    public BinaryStatusCommand(int flag, boolean success) {\n        super(STATUS, true);\n        this.flag = flag;\n        this.success = success;\n    }\n\n    public BinaryStatusCommand() {\n        this(0, false);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        BinaryProtocol.writeInt(out, flag);\n        BinaryProtocol.writeBoolean(out, success);\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        flag = BinaryProtocol.readInt(in);\n        success = BinaryProtocol.readBoolean(in);\n    }\n\n    public int getFlag() {\n        return flag;\n    }\n\n    public void setFlag(int flag) {\n        this.flag = flag;\n    }\n\n    public boolean isSuccess() {\n        return success;\n    }\n\n    public void setSuccess(boolean success) {\n        this.success = success;\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryStringCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Abstract base class for commands that contain a single string payload.\n * This is used for simple commands like EventCommand, RenameCommand, etc.\n */\npublic abstract class BinaryStringCommand extends BinaryCommand {\n    protected String payload;\n\n    protected BinaryStringCommand(byte type, String payload) {\n        super(type, true);\n        this.payload = payload;\n    }\n\n    protected BinaryStringCommand(byte type) {\n        this(type, null);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        BinaryProtocol.writeString(out, payload);\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        payload = BinaryProtocol.readString(in);\n    }\n\n    public String getPayload() {\n        return payload;\n    }\n\n    public void setPayload(String payload) {\n        this.payload = payload;\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryStringMapDataCommand.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * Binary implementation of the StringMapDataCommand.\n * This command is used to send string map data from the BTrace agent to the client.\n */\npublic class BinaryStringMapDataCommand extends BinaryDataCommand {\n    private Map<String, String> data = new LinkedHashMap<>();\n\n    static {\n        // Register this command type\n        BinaryCommand.registerCommand(STRING_MAP, BinaryStringMapDataCommand::new);\n    }\n\n    public BinaryStringMapDataCommand(String name, Map<String, String> data) {\n        super(STRING_MAP, name);\n        if (data != null) {\n            this.data.putAll(data);\n        }\n    }\n\n    public BinaryStringMapDataCommand() {\n        this(null, null);\n    }\n\n    @Override\n    protected void write(OutputStream out) throws IOException {\n        // Write the name\n        super.write(out);\n        \n        // Write the map size\n        BinaryProtocol.writeInt(out, data.size());\n        \n        // Write each map entry\n        for (Map.Entry<String, String> entry : data.entrySet()) {\n            BinaryProtocol.writeString(out, entry.getKey());\n            BinaryProtocol.writeString(out, entry.getValue());\n        }\n    }\n\n    @Override\n    protected void read(InputStream in) throws IOException {\n        // Read the name\n        super.read(in);\n        \n        // Read the map size\n        int size = BinaryProtocol.readInt(in);\n        \n        // Clear any existing data\n        data.clear();\n        \n        // Read each map entry\n        for (int i = 0; i < size; i++) {\n            String key = BinaryProtocol.readString(in);\n            String value = BinaryProtocol.readString(in);\n            data.put(key, value);\n        }\n    }\n\n    public Map<String, String> getData() {\n        return new LinkedHashMap<>(data);\n    }\n\n    public void setData(Map<String, String> data) {\n        this.data.clear();\n        if (data != null) {\n            this.data.putAll(data);\n        }\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/BinaryWireIO.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * Wire I/O implementation for the binary protocol.\n * This replaces the original WireIO class that relied on Java serialization.\n */\npublic class BinaryWireIO {\n    public static final int VERSION = 2;\n\n    // Singleton lock for stream synchronization\n    private static final ReentrantLock writeLock = new ReentrantLock();\n\n    private BinaryWireIO() {}\n\n    /**\n     * Read a command from the input stream\n     */\n    public static BinaryCommand read(InputStream in) throws IOException {\n        // Read the protocol version\n        byte protocolVersion = BinaryProtocol.readByte(in);\n        if (protocolVersion != BinaryProtocol.VERSION) {\n            throw new ProtocolVersionMismatchException(BinaryProtocol.VERSION, protocolVersion);\n        }\n\n        // Read the command type\n        byte type = BinaryProtocol.readByte(in);\n\n        // Create and read the command\n        BinaryCommand cmd;\n        try {\n            cmd = BinaryCommand.createCommand(type);\n        } catch (IllegalArgumentException e) {\n            throw new MalformedCommandException(type, \"Unknown command type\", e);\n        }\n\n        try {\n            cmd.read(in);\n        } catch (IOException e) {\n            throw new CommandDeserializationException(type, e);\n        }\n\n        return cmd;\n    }\n\n    /**\n     * Write a command to the output stream\n     */\n    public static void write(OutputStream out, BinaryCommand cmd) throws IOException {\n        writeLock.lock();\n        try {\n            // Write protocol version\n            BinaryProtocol.writeByte(out, BinaryProtocol.VERSION);\n            \n            // Write command type\n            BinaryProtocol.writeByte(out, cmd.getType());\n            \n            // Write command data\n            cmd.write(out);\n            \n            // Flush if urgent\n            if (cmd.isUrgent()) {\n                out.flush();\n            }\n        } finally {\n            writeLock.unlock();\n        }\n    }\n} "
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/CommandAdapter.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.DisconnectCommand;\nimport org.openjdk.btrace.core.comm.ErrorCommand;\nimport org.openjdk.btrace.core.comm.EventCommand;\nimport org.openjdk.btrace.core.comm.ExitCommand;\nimport org.openjdk.btrace.core.comm.GridDataCommand;\nimport org.openjdk.btrace.core.comm.InstrumentCommand;\nimport org.openjdk.btrace.core.comm.ListProbesCommand;\nimport org.openjdk.btrace.core.comm.ListFailedExtensionsCommand;\nimport org.openjdk.btrace.core.comm.MessageCommand;\nimport org.openjdk.btrace.core.comm.NumberDataCommand;\nimport org.openjdk.btrace.core.comm.NumberMapDataCommand;\nimport org.openjdk.btrace.core.comm.ReconnectCommand;\nimport org.openjdk.btrace.core.comm.RenameCommand;\nimport org.openjdk.btrace.core.comm.RetransformClassNotification;\nimport org.openjdk.btrace.core.comm.RetransformationStartNotification;\nimport org.openjdk.btrace.core.comm.SetSettingsCommand;\nimport org.openjdk.btrace.core.comm.StatusCommand;\nimport org.openjdk.btrace.core.comm.StringMapDataCommand;\n\n/**\n * Adapter for converting between binary commands and original commands.\n * This helps with incremental migration to the new protocol without breaking compatibility.\n */\npublic class CommandAdapter {\n    private CommandAdapter() {}\n    \n    /**\n     * Convert a binary command to an original command\n     */\n    public static Command toBtraceCommand(BinaryCommand binaryCmd) {\n        if (binaryCmd == null) {\n            return Command.NULL;\n        }\n        \n        switch (binaryCmd.getType()) {\n            case BinaryCommand.EXIT:\n                BinaryExitCommand exitCmd = (BinaryExitCommand) binaryCmd;\n                return new ExitCommand(exitCmd.getExitCode());\n                \n            case BinaryCommand.EVENT:\n                BinaryEventCommand eventCmd = (BinaryEventCommand) binaryCmd;\n                return new EventCommand(eventCmd.getEvent());\n                \n            case BinaryCommand.MESSAGE:\n                BinaryMessageCommand msgCmd = (BinaryMessageCommand) binaryCmd;\n                return new MessageCommand(msgCmd.getTimestamp(), msgCmd.getMessage(), msgCmd.isUrgent());\n                \n            case BinaryCommand.INSTRUMENT:\n                BinaryInstrumentCommand instrCmd = (BinaryInstrumentCommand) binaryCmd;\n                return new InstrumentCommand(instrCmd.getCode(), instrCmd.getArguments());\n                \n            case BinaryCommand.ERROR:\n                BinaryErrorCommand errCmd = (BinaryErrorCommand) binaryCmd;\n                Throwable errorCause = null;\n                if (errCmd.getExceptionClass() != null\n                    || errCmd.getMessage() != null\n                    || errCmd.getStackTrace() != null) {\n                    errorCause = new RemoteException(\n                        errCmd.getExceptionClass(), errCmd.getMessage(), errCmd.getStackTrace());\n                }\n                return new ErrorCommand(errorCause);\n                \n            case BinaryCommand.RENAME:\n                BinaryRenameCommand renameCmd = (BinaryRenameCommand) binaryCmd;\n                return new RenameCommand(renameCmd.getNewName());\n                \n            case BinaryCommand.STATUS:\n                BinaryStatusCommand statusCmd = (BinaryStatusCommand) binaryCmd;\n                int flag = statusCmd.getFlag();\n                return new StatusCommand(statusCmd.isSuccess() ? flag : -flag);\n                \n            case BinaryCommand.NUMBER_MAP:\n                BinaryNumberMapDataCommand numMapCmd = (BinaryNumberMapDataCommand) binaryCmd;\n                return new NumberMapDataCommand(numMapCmd.getName(), numMapCmd.getData());\n                \n            case BinaryCommand.STRING_MAP:\n                BinaryStringMapDataCommand strMapCmd = (BinaryStringMapDataCommand) binaryCmd;\n                return new StringMapDataCommand(strMapCmd.getName(), strMapCmd.getData());\n                \n            case BinaryCommand.NUMBER:\n                BinaryNumberDataCommand numCmd = (BinaryNumberDataCommand) binaryCmd;\n                return new NumberDataCommand(numCmd.getName(), numCmd.getValue());\n                \n            case BinaryCommand.GRID_DATA:\n                BinaryGridDataCommand gridCmd = (BinaryGridDataCommand) binaryCmd;\n                GridDataCommand cmd =\n                    new GridDataCommand(\n                        gridCmd.getName(), gridCmd.getColumnNames(), gridCmd.getData());\n                return cmd;\n                \n            case BinaryCommand.RETRANSFORMATION_START:\n                BinaryRetransformationStartNotification retransStartCmd = \n                    (BinaryRetransformationStartNotification) binaryCmd;\n                return new RetransformationStartNotification(retransStartCmd.getNumClasses());\n                \n            case BinaryCommand.RETRANSFORM_CLASS:\n                BinaryRetransformClassNotification retransClassCmd = \n                    (BinaryRetransformClassNotification) binaryCmd;\n                return new RetransformClassNotification(retransClassCmd.getClassName());\n                \n            case BinaryCommand.SET_PARAMS:\n                BinarySetSettingsCommand setParamsCmd = (BinarySetSettingsCommand) binaryCmd;\n                return new SetSettingsCommand(setParamsCmd.getParams());\n                \n            case BinaryCommand.LIST_PROBES:\n                BinaryListProbesCommand listProbesCmd = (BinaryListProbesCommand) binaryCmd;\n                ListProbesCommand listCmd = new ListProbesCommand();\n                listCmd.setProbes(listProbesCmd.getProbes());\n                return listCmd;\n\n            case BinaryCommand.LIST_FAILED_EXTENSIONS:\n                BinaryListFailedExtensionsCommand listFailedCmd =\n                    (BinaryListFailedExtensionsCommand) binaryCmd;\n                ListFailedExtensionsCommand failedCmd = new ListFailedExtensionsCommand();\n                failedCmd.setFailedExtensionsList(listFailedCmd.getFailures());\n                return failedCmd;\n                \n            case BinaryCommand.DISCONNECT:\n                BinaryDisconnectCommand disconnectCmd = (BinaryDisconnectCommand) binaryCmd;\n                return new DisconnectCommand(disconnectCmd.getProbeId());\n                \n            case BinaryCommand.RECONNECT:\n                BinaryReconnectCommand reconnectCmd = (BinaryReconnectCommand) binaryCmd;\n                return new ReconnectCommand(reconnectCmd.getProbeId());\n                \n            default:\n                throw new IllegalArgumentException(\n                    \"Unsupported command type for conversion: \" + binaryCmd.getType());\n        }\n    }\n    \n    /**\n     * Convert an original command to a binary command\n     */\n    public static BinaryCommand toBinaryCommand(Command originalCmd) {\n        if (originalCmd == Command.NULL) {\n            return null;\n        }\n        \n        switch (originalCmd.getType()) {\n            case Command.EXIT:\n                ExitCommand exitCmd = (ExitCommand) originalCmd;\n                return new BinaryExitCommand(exitCmd.getExitCode());\n                \n            case Command.EVENT:\n                EventCommand eventCmd = (EventCommand) originalCmd;\n                return new BinaryEventCommand(eventCmd.getEvent());\n                \n            case Command.MESSAGE:\n                MessageCommand msgCmd = (MessageCommand) originalCmd;\n                return new BinaryMessageCommand(msgCmd.getTime(), msgCmd.getMessage(), originalCmd.isUrgent());\n                \n            case Command.INSTRUMENT:\n                InstrumentCommand instrCmd = (InstrumentCommand) originalCmd;\n                return new BinaryInstrumentCommand(instrCmd.getCode(), instrCmd.getArguments());\n                \n            case Command.ERROR:\n                ErrorCommand errCmd = (ErrorCommand) originalCmd;\n                Throwable cause = errCmd.getCause();\n                String exceptionClass = null;\n                String message = null;\n                String stackTrace = null;\n                if (cause != null) {\n                    exceptionClass = cause.getClass().getName();\n                    message = cause.getMessage();\n                    StringWriter writer = new StringWriter();\n                    PrintWriter printWriter = new PrintWriter(writer);\n                    cause.printStackTrace(printWriter);\n                    printWriter.flush();\n                    stackTrace = writer.toString();\n                }\n                return new BinaryErrorCommand(exceptionClass, message, stackTrace);\n                \n            case Command.RENAME:\n                RenameCommand renameCmd = (RenameCommand) originalCmd;\n                return new BinaryRenameCommand(renameCmd.getNewName());\n                \n            case Command.STATUS:\n                StatusCommand statusCmd = (StatusCommand) originalCmd;\n                return new BinaryStatusCommand(statusCmd.getFlag(), statusCmd.isSuccess());\n                \n            case Command.NUMBER_MAP:\n                NumberMapDataCommand numMapCmd = (NumberMapDataCommand) originalCmd;\n                Map<String, Number> numMap = new LinkedHashMap<>();\n                for (Map.Entry<String, ?> entry : numMapCmd.getData().entrySet()) {\n                    if (entry.getValue() instanceof Number) {\n                        numMap.put(entry.getKey(), (Number) entry.getValue());\n                    }\n                }\n                return new BinaryNumberMapDataCommand(numMapCmd.getName(), numMap);\n                \n            case Command.STRING_MAP:\n                StringMapDataCommand strMapCmd = (StringMapDataCommand) originalCmd;\n                Map<String, String> strMap = new LinkedHashMap<>();\n                for (Map.Entry<String, ?> entry : strMapCmd.getData().entrySet()) {\n                    strMap.put(entry.getKey(), String.valueOf(entry.getValue()));\n                }\n                return new BinaryStringMapDataCommand(strMapCmd.getName(), strMap);\n                \n            case Command.NUMBER:\n                NumberDataCommand numCmd = (NumberDataCommand) originalCmd;\n                return new BinaryNumberDataCommand(numCmd.getName(), numCmd.getValue());\n                \n            case Command.GRID_DATA:\n                GridDataCommand gridCmd = (GridDataCommand) originalCmd;\n                return new BinaryGridDataCommand(\n                    gridCmd.getName(), gridCmd.getColumnNames(), gridCmd.getData());\n                \n            case Command.RETRANSFORMATION_START:\n                RetransformationStartNotification retransStartCmd = \n                    (RetransformationStartNotification) originalCmd;\n                return new BinaryRetransformationStartNotification(retransStartCmd.getNumClasses());\n                \n            case Command.RETRANSFORM_CLASS:\n                RetransformClassNotification retransClassCmd = \n                    (RetransformClassNotification) originalCmd;\n                return new BinaryRetransformClassNotification(retransClassCmd.getClassName(), 0, 0);\n                \n            case Command.SET_PARAMS:\n                SetSettingsCommand setParamsCmd = (SetSettingsCommand) originalCmd;\n                return new BinarySetSettingsCommand(setParamsCmd.getParams());\n                \n            case Command.LIST_PROBES:\n                ListProbesCommand listProbesCmd = (ListProbesCommand) originalCmd;\n                BinaryListProbesCommand listCmd = new BinaryListProbesCommand();\n                listCmd.setProbes(listProbesCmd.getProbes());\n                return listCmd;\n                \n            case Command.DISCONNECT:\n                DisconnectCommand disconnectCmd = (DisconnectCommand) originalCmd;\n                return new BinaryDisconnectCommand(disconnectCmd.getProbeId());\n                \n            case Command.RECONNECT:\n                ReconnectCommand reconnectCmd = (ReconnectCommand) originalCmd;\n                return new BinaryReconnectCommand(reconnectCmd.getProbeId());\n\n            case Command.LIST_FAILED_EXTENSIONS:\n                ListFailedExtensionsCommand listFailedCmd = (ListFailedExtensionsCommand) originalCmd;\n                BinaryListFailedExtensionsCommand binaryFailedCmd =\n                    new BinaryListFailedExtensionsCommand();\n                binaryFailedCmd.setFailures(listFailedCmd.getFailedExtensions());\n                return binaryFailedCmd;\n                \n            default:\n                throw new IllegalArgumentException(\n                    \"Unsupported command type for conversion: \" + originalCmd.getType());\n        }\n    }\n} \n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/CommandDeserializationException.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\n\n/**\n * Exception thrown when deserialization of a command fails.\n */\npublic class CommandDeserializationException extends IOException {\n    private final byte commandType;\n\n    public CommandDeserializationException(byte commandType, String message, Throwable cause) {\n        super(String.format(\"Failed to deserialize command (type=%d): %s\",\n            commandType, message), cause);\n        this.commandType = commandType;\n    }\n\n    public CommandDeserializationException(byte commandType, Throwable cause) {\n        super(String.format(\"Failed to deserialize command (type=%d)\", commandType), cause);\n        this.commandType = commandType;\n    }\n\n    public byte getCommandType() {\n        return commandType;\n    }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/MalformedCommandException.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\n\n/**\n * Exception thrown when a command has invalid structure or data.\n */\npublic class MalformedCommandException extends IOException {\n    private final byte commandType;\n\n    public MalformedCommandException(byte commandType, String message) {\n        super(String.format(\"Malformed command (type=%d): %s\", commandType, message));\n        this.commandType = commandType;\n    }\n\n    public MalformedCommandException(byte commandType, String message, Throwable cause) {\n        super(String.format(\"Malformed command (type=%d): %s\", commandType, message), cause);\n        this.commandType = commandType;\n    }\n\n    public byte getCommandType() {\n        return commandType;\n    }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/NumberEncoding.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\n\n/**\n * Small helper to unify encoding of numeric values (null, int, long, float, double)\n * across binary commands that share the same type code mapping.\n */\nfinal class NumberEncoding {\n  private final byte nullCode;\n  private final byte intCode;\n  private final byte longCode;\n  private final byte floatCode;\n  private final byte doubleCode;\n  private final byte bigIntegerCode;\n  private final byte bigDecimalCode;\n\n  NumberEncoding(\n      byte nullCode,\n      byte intCode,\n      byte longCode,\n      byte floatCode,\n      byte doubleCode,\n      byte bigIntegerCode,\n      byte bigDecimalCode) {\n    this.nullCode = nullCode;\n    this.intCode = intCode;\n    this.longCode = longCode;\n    this.floatCode = floatCode;\n    this.doubleCode = doubleCode;\n    this.bigIntegerCode = bigIntegerCode;\n    this.bigDecimalCode = bigDecimalCode;\n  }\n\n  void writeNumber(OutputStream out, Number value) throws IOException {\n    if (value == null) {\n      BinaryProtocol.writeByte(out, nullCode);\n      return;\n    }\n    if (value instanceof Integer) {\n      BinaryProtocol.writeByte(out, intCode);\n      BinaryProtocol.writeInt(out, (Integer) value);\n    } else if (value instanceof Long) {\n      BinaryProtocol.writeByte(out, longCode);\n      BinaryProtocol.writeLong(out, (Long) value);\n    } else if (value instanceof Float) {\n      BinaryProtocol.writeByte(out, floatCode);\n      BinaryProtocol.writeFloat(out, (Float) value);\n    } else if (value instanceof Double) {\n      BinaryProtocol.writeByte(out, doubleCode);\n      BinaryProtocol.writeDouble(out, (Double) value);\n    } else if (value instanceof BigInteger) {\n      BinaryProtocol.writeByte(out, bigIntegerCode);\n      BinaryProtocol.writeString(out, value.toString());\n    } else if (value instanceof BigDecimal) {\n      BinaryProtocol.writeByte(out, bigDecimalCode);\n      BinaryProtocol.writeString(out, value.toString());\n    } else {\n      // Default to long for other number implementations\n      BinaryProtocol.writeByte(out, longCode);\n      BinaryProtocol.writeLong(out, value.longValue());\n    }\n  }\n\n  Number readNumber(InputStream in) throws IOException {\n    byte type = BinaryProtocol.readByte(in);\n    if (type == nullCode) {\n      return null;\n    } else if (type == intCode) {\n      return BinaryProtocol.readInt(in);\n    } else if (type == longCode) {\n      return BinaryProtocol.readLong(in);\n    } else if (type == floatCode) {\n      return BinaryProtocol.readFloat(in);\n    } else if (type == doubleCode) {\n      return BinaryProtocol.readDouble(in);\n    } else if (type == bigIntegerCode) {\n      return new BigInteger(BinaryProtocol.readString(in));\n    } else if (type == bigDecimalCode) {\n      return new BigDecimal(BinaryProtocol.readString(in));\n    } else {\n      throw new IOException(\"Unsupported number type: \" + type);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/ProtocolVersionMismatchException.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\n\n/**\n * Exception thrown when the protocol version in the stream doesn't match\n * the expected version.\n */\npublic class ProtocolVersionMismatchException extends IOException {\n    private final int expectedVersion;\n    private final int actualVersion;\n\n    public ProtocolVersionMismatchException(int expectedVersion, int actualVersion) {\n        super(String.format(\"Protocol version mismatch: expected %d, got %d\",\n            expectedVersion, actualVersion));\n        this.expectedVersion = expectedVersion;\n        this.actualVersion = actualVersion;\n    }\n\n    public int getExpectedVersion() {\n        return expectedVersion;\n    }\n\n    public int getActualVersion() {\n        return actualVersion;\n    }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/README.md",
    "content": "# BTrace Binary Protocol (v2)\n\nThis package contains a new binary protocol implementation for BTrace that replaces the original Java serialization-based protocol with a more efficient binary format.\n\n## Benefits\n\n- **Improved Performance**: Custom binary serialization is significantly faster than Java serialization\n- **Reduced Memory Usage**: Binary format is more compact than Java serialization\n- **Compression Support**: Large messages and code payloads are automatically compressed\n- **Thread Safety**: Uses ReentrantLock instead of synchronized blocks for better scalability\n- **Versioning**: Protocol includes version information for future compatibility\n- **Extensibility**: Registry pattern makes it easy to add new command types\n- **Backward Compatibility**: Adapter layer allows gradual migration\n\n## Protocol Format\n\nEach command in the binary protocol has the following format:\n\n```\n+----------------+----------------+--------------------+\n| Protocol Version (1 byte) | Command Type (1 byte) | Command Data |\n+----------------+----------------+--------------------+\n```\n\nThe Command Data format depends on the Command Type and is defined by each command implementation.\n\n## Command Types\n\nThe binary protocol supports all the command types from the original protocol:\n\n| Type | Command | Description |\n|------|---------|-------------|\n| 0 | ERROR | Error notification |\n| 1 | EVENT | Event trigger |\n| 2 | EXIT | Exit command |\n| 3 | INSTRUMENT | Instrumentation code |\n| 4 | MESSAGE | Text message |\n| 5 | RENAME | Rename command |\n| 6 | STATUS | Status information |\n| 7 | NUMBER_MAP | Number map data |\n| 8 | STRING_MAP | String map data |\n| 9 | NUMBER | Number data |\n| 10 | GRID_DATA | Grid/tabular data |\n| 11 | RETRANSFORMATION_START | Class retransformation start |\n| 12 | RETRANSFORM_CLASS | Class retransformation notification |\n| 13 | SET_PARAMS | Settings parameters |\n| 14 | LIST_PROBES | List probes command |\n| 15 | DISCONNECT | Disconnect command |\n| 16 | RECONNECT | Reconnect command |\n| 17 | LIST_FAILED_EXTENSIONS | List failed extensions command |\n\n## Data Types\n\nThe binary protocol supports the following data types:\n\n- byte, int, long, float, double\n- boolean\n- String (UTF-8 encoded with length prefix)\n- byte[] (with length prefix)\n- Nested data structures (maps, lists, etc.)\n\n## Compression\n\nLarge payloads (like message text and instrumentation code) are automatically compressed using Java's Deflater/Inflater with BEST_SPEED setting. The compression threshold is configurable.\n\n## Migration\n\nUse the `CommandAdapter` class to convert between binary commands and original commands:\n\n```java\n// Convert original command to binary command\nBinaryCommand binaryCmd = CommandAdapter.toBinaryCommand(originalCmd);\n\n// Convert binary command to original command\nCommand originalCmd = CommandAdapter.toBtraceCommand(binaryCmd);\n```\n\nFor applications using the core BTrace API directly, use `BinaryClient` instead of the original client:\n\n```java\n// Create a binary client\nBinaryClient client = new BinaryClient(inputStream, outputStream, commandListener);\n\n// Send a command\nclient.sendMessage(\"Hello, World!\", true);\n\n// Process commands\nclient.commandLoop();\n```\n\n## Performance Comparison\n\nPerformance tests show that the binary protocol is significantly more efficient than the original Java serialization-based protocol:\n\n| Command | Time Improvement | Size Improvement |\n|---------|-----------------|------------------|\n| InstrumentCommand | 3-5x faster | 2-3x smaller |\n| MessageCommand | 4-6x faster | 3-5x smaller (with compression) |\n\n## Implementation\n\nThe implementation follows a clean, object-oriented design:\n\n- `BinaryProtocol`: Low-level binary serialization utilities\n- `BinaryCommand`: Base class for all commands\n- `BinaryWireIO`: Wire protocol implementation\n- `BinaryClient`: Client wrapper for the binary protocol\n- Command implementations: One class per command type\n- `CommandAdapter`: Conversion between binary and original commands\n\n## Future Enhancements\n\n- Add more compression algorithms (LZ4, Snappy)\n- Implement batching for multiple commands\n- Add flow control and backpressure handling\n- Add direct ByteBuffer support for zero-copy operations\n- Implement multiplexing for multiple concurrent clients\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/RemoteException.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.PrintStream;\nimport java.io.PrintWriter;\n\nclass RemoteException extends RuntimeException {\n    private final String exceptionClass;\n    private final String remoteStackTrace;\n\n    RemoteException(String exceptionClass, String message, String remoteStackTrace) {\n        super(message);\n        this.exceptionClass = exceptionClass;\n        this.remoteStackTrace = remoteStackTrace;\n    }\n\n    @Override\n    public void printStackTrace(PrintWriter s) {\n        if (remoteStackTrace != null) {\n            s.print(remoteStackTrace);\n            return;\n        }\n        super.printStackTrace(s);\n    }\n\n    @Override\n    public void printStackTrace(PrintStream s) {\n        if (remoteStackTrace != null) {\n            s.print(remoteStackTrace);\n            return;\n        }\n        super.printStackTrace(s);\n    }\n\n    @Override\n    public String toString() {\n        if (exceptionClass == null) {\n            return super.toString();\n        }\n        String message = getMessage();\n        return message == null ? exceptionClass : exceptionClass + \": \" + message;\n    }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/ScalarEncoding.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n\n/**\n * Helper to encode/decode common scalar types with configurable type codes.\n * Supported: null, String, Integer, Long, Float, Double, Boolean.\n */\nfinal class ScalarEncoding {\n  private final byte nullCode;\n  private final byte stringCode;\n  private final byte intCode;\n  private final byte longCode;\n  private final byte floatCode;\n  private final byte doubleCode;\n  private final byte booleanCode;\n  ScalarEncoding(\n      byte nullCode,\n      byte stringCode,\n      byte intCode,\n      byte longCode,\n      byte floatCode,\n      byte doubleCode,\n      byte booleanCode) {\n    this.nullCode = nullCode;\n    this.stringCode = stringCode;\n    this.intCode = intCode;\n    this.longCode = longCode;\n    this.floatCode = floatCode;\n    this.doubleCode = doubleCode;\n    this.booleanCode = booleanCode;\n  }\n\n  void writeValue(OutputStream out, Object value) throws IOException {\n    if (value == null) {\n      BinaryProtocol.writeByte(out, nullCode);\n      return;\n    }\n    if (value instanceof String) {\n      BinaryProtocol.writeByte(out, stringCode);\n      BinaryProtocol.writeString(out, (String) value);\n    } else if (value instanceof Integer) {\n      BinaryProtocol.writeByte(out, intCode);\n      BinaryProtocol.writeInt(out, (Integer) value);\n    } else if (value instanceof Long) {\n      BinaryProtocol.writeByte(out, longCode);\n      BinaryProtocol.writeLong(out, (Long) value);\n    } else if (value instanceof Float) {\n      BinaryProtocol.writeByte(out, floatCode);\n      BinaryProtocol.writeFloat(out, (Float) value);\n    } else if (value instanceof Double) {\n      BinaryProtocol.writeByte(out, doubleCode);\n      BinaryProtocol.writeDouble(out, (Double) value);\n    } else if (value instanceof Boolean) {\n      BinaryProtocol.writeByte(out, booleanCode);\n      BinaryProtocol.writeBoolean(out, (Boolean) value);\n    } else {\n      // Fallback: write as string\n      BinaryProtocol.writeByte(out, stringCode);\n      BinaryProtocol.writeString(out, value.toString());\n    }\n  }\n\n  Object readValue(InputStream in) throws IOException {\n    byte type = BinaryProtocol.readByte(in);\n    if (type == nullCode) {\n      return null;\n    } else if (type == stringCode) {\n      return BinaryProtocol.readString(in);\n    } else if (type == intCode) {\n      return BinaryProtocol.readInt(in);\n    } else if (type == longCode) {\n      return BinaryProtocol.readLong(in);\n    } else if (type == floatCode) {\n      return BinaryProtocol.readFloat(in);\n    } else if (type == doubleCode) {\n      return BinaryProtocol.readDouble(in);\n    } else if (type == booleanCode) {\n      return BinaryProtocol.readBoolean(in);\n    } else {\n      throw new IOException(\"Unsupported scalar type: \" + type);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/extensions/Extension.java",
    "content": "package org.openjdk.btrace.core.extensions;\n\n/**\n * Base class for all BTrace extensions.\n *\n * <p>Extensions provide additional functionality to BTrace scripts beyond the core BTraceUtils API.\n * They declare required permissions via descriptors and implement proper lifecycle management.\n *\n * <p><b>Lifecycle:</b>\n *\n * <ol>\n *   <li>Extension is instantiated via no-arg constructor\n *   <li>{@link #initialize(ExtensionContext)} is called once\n *   <li>Extension methods are called by BTrace script\n *   <li>{@link #close()} is called when script detaches\n * </ol>\n *\n * <p><b>Thread Safety:</b> Extensions must be thread-safe as they may be called concurrently from\n * multiple instrumented threads.\n *\n * <p><b>Example:</b>\n *\n * <pre>\n * public class ExampleExtension extends Extension {\n *   private Socket socket;\n *\n *   &#64;Override\n *   public void initialize(ExtensionContext ctx) {\n *     super.initialize(ctx);\n *     socket = new Socket(...);\n *   }\n *\n *   public void sendData(String data) {\n *     // Extension functionality\n *   }\n *\n *   &#64;Override\n *   public void close() {\n *     if (socket != null) {\n *       socket.close();\n *     }\n *   }\n * }\n * </pre>\n */\npublic abstract class Extension implements AutoCloseable {\n  private volatile ExtensionContext context;\n\n  /**\n   * Initializes this extension with the provided context.\n   *\n   * <p>Called once after construction, before any extension methods are invoked. Implementations\n   * should perform initialization that requires access to the runtime context (e.g., acquiring\n   * resources, starting threads).\n   *\n   * <p>This method is called by the BTrace runtime and should not be invoked directly.\n   *\n   * @param ctx the extension context\n   * @throws ExtensionException if initialization fails\n   */\n  public void initialize(ExtensionContext ctx) throws ExtensionException {\n    this.context = ctx;\n  }\n\n  /**\n   * Releases resources held by this extension.\n   *\n   * <p>Called when the BTrace script detaches. Implementations must clean up all resources (close\n   * sockets, stop threads, release buffers, etc.).\n   *\n   * <p>This method is called by the BTrace runtime and should not be invoked directly.\n   *\n   * <p>Implementations should not throw exceptions. If cleanup fails, errors should be logged but\n   * not propagated.\n   */\n  @Override\n  public void close() {\n    // Default: no cleanup needed\n  }\n\n  /**\n   * Returns the extension context.\n   *\n   * @return the context provided at initialization\n   * @throws IllegalStateException if called before {@link #initialize(ExtensionContext)}\n   */\n  protected final ExtensionContext getContext() {\n    if (context == null) {\n      throw new IllegalStateException(\"Extension not initialized\");\n    }\n    return context;\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/extensions/ExtensionContext.java",
    "content": "package org.openjdk.btrace.core.extensions;\n\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.comm.Command;\n\n/**\n * Context provided to extensions at initialization.\n *\n * <p>Extensions use this context to access BTrace runtime services such as messaging, script\n * arguments, and permission checking.\n */\npublic interface ExtensionContext {\n  /**\n   * Sends a message to the BTrace client.\n   *\n   * @param message the message text\n   */\n  void send(String message);\n\n  /**\n   * Sends a command to the BTrace client.\n   *\n   * @param command the command to send\n   */\n  void send(Command command);\n\n  /**\n   * Returns the script arguments.\n   *\n   * @return script arguments map\n   */\n  ArgsMap getArgs();\n\n  /**\n   * Returns the fully qualified name of the script class using this extension.\n   *\n   * @return script class name\n   */\n  String getScriptClassName();\n\n  /**\n   * Returns the permissions granted to the script.\n   *\n   * @return permission set\n   */\n  PermissionSet getPermissions();\n\n  /**\n   * Checks if the script has the specified permission.\n   *\n   * @param permission the permission to check\n   * @return true if the permission is granted\n   */\n  boolean hasPermission(Permission permission);\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/extensions/ExtensionDescriptor.java",
    "content": "package org.openjdk.btrace.core.extensions;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Describes metadata for a BTrace extension (package-level, optional).\n *\n * <p>Place this annotation in your API module's `package-info.java` to document the extension.\n * Manifest entries generated by the Gradle plugin remain the single source of truth.\n */\n@Target(ElementType.PACKAGE)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface ExtensionDescriptor {\n  /**\n   * The unique name of this extension.\n   *\n   * @return extension name\n   */\n  String name();\n\n  /**\n   * The version of this extension.\n   *\n   * @return version string (e.g., \"1.0\", \"2.1.0\")\n   */\n  String version();\n\n  /**\n   * Human-readable description of this extension.\n   *\n   * @return description text\n   */\n  String description() default \"\";\n\n  /**\n   * Minimum BTrace version required by this extension.\n   *\n   * @return minimum BTrace version (e.g., \"2.1\")\n   */\n  String minBTraceVersion() default \"\";\n\n  /**\n   * Other extensions that must be available for this extension to function.\n   *\n   * @return array of required extension classes\n   */\n  Class<? extends Extension>[] dependencies() default {};\n\n  /**\n   * Permissions required by this extension as a whole.\n   *\n   * <p>These are combined with permissions declared on individual services via\n   * {@link ServiceDescriptor#permissions()} when computing the effective permission set.\n   */\n  Permission[] permissions() default {};\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/extensions/ExtensionException.java",
    "content": "package org.openjdk.btrace.core.extensions;\n\n/**\n * Exception thrown when extension operations fail.\n *\n * <p>This exception is used for extension-related errors including:\n *\n * <ul>\n *   <li>Missing or invalid extension annotations\n *   <li>Permission violations\n *   <li>Initialization failures\n *   <li>Missing dependencies\n * </ul>\n */\npublic class ExtensionException extends RuntimeException {\n  /**\n   * Constructs an exception with the specified message.\n   *\n   * @param message the error message\n   */\n  public ExtensionException(String message) {\n    super(message);\n  }\n\n  /**\n   * Constructs an exception with the specified message and cause.\n   *\n   * @param message the error message\n   * @param cause the underlying cause\n   */\n  public ExtensionException(String message, Throwable cause) {\n    super(message, cause);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/extensions/ExtensionMeta.java",
    "content": "package org.openjdk.btrace.core.extensions;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Metadata extracted from an extension class.\n *\n * <p>This class holds immutable metadata parsed from package-level {@link ExtensionDescriptor}\n * (if available).\n */\npublic final class ExtensionMeta {\n  private final Class<? extends Extension> extensionClass;\n  private final String name;\n  private final String version;\n  private final String description;\n  private final String minBTraceVersion;\n  private final PermissionSet requiredPermissions;\n  private final Set<Class<? extends Extension>> dependencies;\n\n  private ExtensionMeta(\n      Class<? extends Extension> extensionClass,\n      String name,\n      String version,\n      String description,\n      String minBTraceVersion,\n      PermissionSet requiredPermissions,\n      Set<Class<? extends Extension>> dependencies) {\n    this.extensionClass = extensionClass;\n    this.name = name;\n    this.version = version;\n    this.description = description;\n    this.minBTraceVersion = minBTraceVersion;\n    this.requiredPermissions = requiredPermissions;\n    this.dependencies = dependencies;\n  }\n\n  /**\n   * Extracts metadata from an extension class.\n   *\n   * @param extensionClass the extension class\n   * @return extracted metadata\n   * Builds metadata from package-level {@link ExtensionDescriptor} when present.\n  */\n  public static ExtensionMeta from(Class<? extends Extension> extensionClass) {\n    // Prefer package-level descriptor for identity and extension-level permissions\n    Package pkg = extensionClass.getPackage();\n    ExtensionDescriptor pkgDesc = pkg != null ? pkg.getAnnotation(ExtensionDescriptor.class) : null;\n\n    String name = (pkgDesc != null && !pkgDesc.name().isEmpty()) ? pkgDesc.name() : extensionClass.getSimpleName();\n    String version = (pkgDesc != null) ? pkgDesc.version() : \"\";\n    String description = (pkgDesc != null) ? pkgDesc.description() : \"\";\n    String minBTraceVersion = (pkgDesc != null) ? pkgDesc.minBTraceVersion() : \"\";\n\n    // Extract required permissions (pkg-level)\n    Set<Permission> permissions = new HashSet<>();\n    if (pkgDesc != null) {\n      for (Permission p : pkgDesc.permissions()) {\n        if (p != null) permissions.add(p);\n      }\n    }\n\n    PermissionSet permissionSet =\n        permissions.isEmpty()\n            ? PermissionSet.empty()\n            : PermissionSet.of(permissions.toArray(new Permission[0]));\n\n    return new ExtensionMeta(\n        extensionClass,\n        name,\n        version,\n        description,\n        minBTraceVersion,\n        permissionSet,\n        Collections.emptySet());\n  }\n\n  /**\n   * Returns the extension class.\n   *\n   * @return extension class\n   */\n  public Class<? extends Extension> getExtensionClass() {\n    return extensionClass;\n  }\n\n  /**\n   * Returns the extension name.\n   *\n   * @return name\n   */\n  public String getName() {\n    return name;\n  }\n\n  /**\n   * Returns the extension version.\n   *\n   * @return version string\n   */\n  public String getVersion() {\n    return version;\n  }\n\n  /**\n   * Returns the extension description.\n   *\n   * @return description text\n   */\n  public String getDescription() {\n    return description;\n  }\n\n  /**\n   * Returns the minimum required BTrace version.\n   *\n   * @return minimum BTrace version\n   */\n  public String getMinBTraceVersion() {\n    return minBTraceVersion;\n  }\n\n  /**\n   * Returns the required permissions.\n   *\n   * @return permission set\n   */\n  public PermissionSet getRequiredPermissions() {\n    return requiredPermissions;\n  }\n\n  /**\n   * Returns the extension dependencies.\n   *\n   * @return set of required extension classes\n   */\n  public Set<Class<? extends Extension>> getDependencies() {\n    return dependencies;\n  }\n\n  @Override\n  public String toString() {\n    return \"ExtensionMeta{\"\n        + \"name='\"\n        + name\n        + '\\''\n        + \", version='\"\n        + version\n        + '\\''\n        + \", permissions=\"\n        + requiredPermissions\n        + '}';\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/extensions/Permission.java",
    "content": "package org.openjdk.btrace.core.extensions;\n\n/**\n * Permissions that can be requested by BTrace extensions.\n *\n * <p>Permissions are organized into three tiers:\n *\n * <ul>\n *   <li><b>Default</b> - Always granted, core BTrace functionality\n *   <li><b>Standard</b> - Granted unless explicitly restricted\n *   <li><b>Privileged</b> - Require explicit user consent\n * </ul>\n */\npublic enum Permission {\n  // Default permissions - always granted\n  /** Permission to send messages to the BTrace client */\n  MESSAGING,\n  /** Permission to use aggregation functions */\n  AGGREGATION,\n  /** Permission to create and use JFR events */\n  JFR_EVENTS,\n  /** Permission to use profiling functions */\n  PROFILING,\n\n  // Standard permissions - granted unless restricted\n  /** Permission to read files (limited to specific paths) */\n  FILE_READ,\n  /** Permission to read system properties */\n  SYSTEM_PROPS,\n  /** Permission to read thread information */\n  THREAD_INFO,\n  /** Permission to read memory and GC information */\n  MEMORY_INFO,\n\n  // Privileged permissions - require explicit consent\n  /** Permission to write to files */\n  FILE_WRITE,\n  /** Permission for network I/O (sockets, HTTP) */\n  NETWORK,\n  /** Permission to create and manage threads */\n  THREADS,\n  /** Permission to call native code (JNI, Unsafe) */\n  NATIVE,\n  /** Permission to execute external processes */\n  EXEC,\n  /** Permission to use reflection */\n  REFLECTION,\n  /** Permission to access classloaders */\n  CLASSLOADER,\n  /** Permission for unlimited buffer allocation */\n  UNLIMITED_MEMORY;\n\n  /**\n   * Returns whether this is a default permission.\n   *\n   * @return true if this permission is always granted\n   */\n  public boolean isDefault() {\n    return ordinal() <= PROFILING.ordinal();\n  }\n\n  /**\n   * Returns whether this is a standard permission.\n   *\n   * @return true if this permission is granted unless restricted\n   */\n  public boolean isStandard() {\n    return ordinal() > PROFILING.ordinal() && ordinal() <= MEMORY_INFO.ordinal();\n  }\n\n  /**\n   * Returns whether this is a privileged permission.\n   *\n   * @return true if this permission requires explicit consent\n   */\n  public boolean isPrivileged() {\n    return ordinal() > MEMORY_INFO.ordinal();\n  }\n\n  /**\n   * Returns a description of the security risk associated with this permission.\n   *\n   * @return risk description for user warning\n   */\n  public String getRiskDescription() {\n    switch (this) {\n      case MESSAGING:\n        return \"Send messages to BTrace client. Low risk.\";\n      case AGGREGATION:\n        return \"Use aggregation functions. Low risk.\";\n      case JFR_EVENTS:\n        return \"Create JFR events. Low risk.\";\n      case PROFILING:\n        return \"Use profiling functions. Low risk.\";\n      case FILE_READ:\n        return \"Read files from disk. Risk: Information disclosure.\";\n      case SYSTEM_PROPS:\n        return \"Read system properties. Risk: Information disclosure.\";\n      case THREAD_INFO:\n        return \"Read thread information. Risk: Information disclosure.\";\n      case MEMORY_INFO:\n        return \"Read memory/GC information. Risk: Information disclosure.\";\n      case FILE_WRITE:\n        return \"Write files to disk. Risk: Data modification, disk exhaustion.\";\n      case NETWORK:\n        return \"Network I/O (sockets, HTTP). Risk: Data exfiltration, remote connections.\";\n      case THREADS:\n        return \"Create and manage threads. Risk: Resource exhaustion, concurrent operations.\";\n      case NATIVE:\n        return \"Call native code (JNI, Unsafe). Risk: JVM crashes, memory corruption.\";\n      case EXEC:\n        return \"Execute external processes. Risk: Arbitrary command execution.\";\n      case REFLECTION:\n        return \"Use reflection. Risk: Bypass access controls.\";\n      case CLASSLOADER:\n        return \"Access classloaders. Risk: Load arbitrary code.\";\n      case UNLIMITED_MEMORY:\n        return \"Unlimited buffer allocation. Risk: Memory exhaustion.\";\n      default:\n        return \"Unknown permission.\";\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/extensions/PermissionSet.java",
    "content": "package org.openjdk.btrace.core.extensions;\n\nimport java.util.EnumSet;\nimport java.util.Iterator;\n\n/**\n * Immutable set of permissions.\n *\n * <p>This class provides an efficient, allocation-free way to check permissions and create derived\n * permission sets.\n */\npublic final class PermissionSet implements Iterable<Permission> {\n  private static final PermissionSet EMPTY = new PermissionSet(EnumSet.noneOf(Permission.class));\n  private static final PermissionSet ALL = new PermissionSet(EnumSet.allOf(Permission.class));\n  private static final PermissionSet DEFAULT;\n  private static final PermissionSet STANDARD;\n\n  static {\n    EnumSet<Permission> defaultPerms = EnumSet.noneOf(Permission.class);\n    EnumSet<Permission> standardPerms = EnumSet.noneOf(Permission.class);\n    for (Permission p : Permission.values()) {\n      if (p.isDefault()) {\n        defaultPerms.add(p);\n      }\n      if (p.isDefault() || p.isStandard()) {\n        standardPerms.add(p);\n      }\n    }\n    DEFAULT = new PermissionSet(defaultPerms);\n    STANDARD = new PermissionSet(standardPerms);\n  }\n\n  private final EnumSet<Permission> permissions;\n\n  private PermissionSet(EnumSet<Permission> permissions) {\n    this.permissions = EnumSet.copyOf(permissions);\n  }\n\n  /**\n   * Returns an empty permission set.\n   *\n   * @return empty permission set\n   */\n  public static PermissionSet empty() {\n    return EMPTY;\n  }\n\n  /**\n   * Returns a permission set containing all permissions.\n   *\n   * @return permission set with all permissions\n   */\n  public static PermissionSet all() {\n    return ALL;\n  }\n\n  /**\n   * Returns a permission set containing default permissions.\n   *\n   * @return permission set with default permissions\n   */\n  public static PermissionSet defaults() {\n    return DEFAULT;\n  }\n\n  /**\n   * Returns a permission set containing default and standard permissions.\n   *\n   * @return permission set with default and standard permissions\n   */\n  public static PermissionSet standard() {\n    return STANDARD;\n  }\n\n  /**\n   * Returns a permission set containing the specified permissions.\n   *\n   * @param permissions the permissions to include\n   * @return new permission set\n   */\n  public static PermissionSet of(Permission... permissions) {\n    if (permissions.length == 0) {\n      return EMPTY;\n    }\n    EnumSet<Permission> set = EnumSet.noneOf(Permission.class);\n    for (Permission p : permissions) {\n      set.add(p);\n    }\n    return new PermissionSet(set);\n  }\n\n  /**\n   * Checks if this set contains the specified permission.\n   *\n   * @param permission the permission to check\n   * @return true if the permission is present\n   */\n  public boolean has(Permission permission) {\n    return permissions.contains(permission);\n  }\n\n  /**\n   * Checks if this set contains all of the specified permissions.\n   *\n   * @param other the permission set to check\n   * @return true if all permissions are present\n   */\n  public boolean hasAll(PermissionSet other) {\n    return permissions.containsAll(other.permissions);\n  }\n\n  /**\n   * Returns a new permission set with the specified permissions added.\n   *\n   * @param toAdd the permissions to add\n   * @return new permission set\n   */\n  public PermissionSet with(Permission... toAdd) {\n    if (toAdd.length == 0) {\n      return this;\n    }\n    EnumSet<Permission> newSet = EnumSet.copyOf(permissions);\n    for (Permission p : toAdd) {\n      newSet.add(p);\n    }\n    return new PermissionSet(newSet);\n  }\n\n  /**\n   * Returns a new permission set with the specified permissions removed.\n   *\n   * @param toRemove the permissions to remove\n   * @return new permission set\n   */\n  public PermissionSet without(Permission... toRemove) {\n    if (toRemove.length == 0) {\n      return this;\n    }\n    EnumSet<Permission> newSet = EnumSet.copyOf(permissions);\n    for (Permission p : toRemove) {\n      newSet.remove(p);\n    }\n    return new PermissionSet(newSet);\n  }\n\n  /**\n   * Returns the number of permissions in this set.\n   *\n   * @return permission count\n   */\n  public int size() {\n    return permissions.size();\n  }\n\n  /**\n   * Returns whether this set is empty.\n   *\n   * @return true if no permissions are present\n   */\n  public boolean isEmpty() {\n    return permissions.isEmpty();\n  }\n\n  @Override\n  public Iterator<Permission> iterator() {\n    return permissions.iterator();\n  }\n\n  @Override\n  public boolean equals(Object obj) {\n    if (this == obj) {\n      return true;\n    }\n    if (!(obj instanceof PermissionSet)) {\n      return false;\n    }\n    PermissionSet other = (PermissionSet) obj;\n    return permissions.equals(other.permissions);\n  }\n\n  @Override\n  public int hashCode() {\n    return permissions.hashCode();\n  }\n\n  @Override\n  public String toString() {\n    return permissions.toString();\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/extensions/ServiceDescriptor.java",
    "content": "package org.openjdk.btrace.core.extensions;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Marks a type as an injectable BTrace service API.\n *\n * <p>Annotate public top-level interfaces in an extension's API module that are intended to be\n * injected into BTrace scripts via {@code @Injected}.\n *\n * <p>The BTrace Gradle extension plugin scans for this annotation in the API output and generates\n * the appropriate manifest entries (BTrace-Extension-Services). The compiler/verifier framework can\n * rely on the agent-provided service declaration registry (populated from these manifests) to\n * enforce that only declared service APIs are injected.</p>\n *\n * <p>You may also declare service-level permissions here. These combine with extension-level\n * permissions from {@link ExtensionDescriptor#permissions()} to form the effective permission set.</p>\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface ServiceDescriptor {\n  Permission[] permissions() default {};\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/handlers/ErrorHandler.java",
    "content": "package org.openjdk.btrace.core.handlers;\n\nimport java.lang.reflect.Method;\n\npublic final class ErrorHandler {\n  public final String method;\n\n  public ErrorHandler(String method) {\n    this.method = method;\n  }\n\n  public Method getMethod(Class<?> clz) throws NoSuchMethodException {\n    return clz.getMethod(method, Throwable.class);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/handlers/EventHandler.java",
    "content": "package org.openjdk.btrace.core.handlers;\n\nimport java.lang.reflect.Method;\n\npublic final class EventHandler {\n  public static final String ALL_EVENTS = \"\";\n\n  public final String method;\n  private final String event;\n\n  public EventHandler(String method, String event) {\n    this.method = method;\n    this.event = event;\n  }\n\n  public String getEvent() {\n    return event != null ? event : ALL_EVENTS;\n  }\n\n  public Method getMethod(Class<?> clz) throws NoSuchMethodException {\n    return clz.getMethod(method);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/handlers/ExitHandler.java",
    "content": "package org.openjdk.btrace.core.handlers;\n\nimport java.lang.reflect.Method;\n\npublic class ExitHandler {\n  public final String method;\n\n  public ExitHandler(String method) {\n    this.method = method;\n  }\n\n  public Method getMethod(Class<?> clz) throws NoSuchMethodException {\n    return clz.getMethod(method, int.class);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/handlers/LowMemoryHandler.java",
    "content": "package org.openjdk.btrace.core.handlers;\n\nimport java.lang.management.MemoryUsage;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\npublic final class LowMemoryHandler {\n  public final String method;\n  public final String pool;\n  public final String thresholdProperty;\n  public final long threshold;\n  public final boolean trackUsage;\n  private Method executable;\n\n  public LowMemoryHandler(\n      String method, String pool, long threshold, String thresholdProperty, boolean trackUsage) {\n    this.method = method;\n    this.pool = pool;\n    this.threshold = threshold;\n    this.thresholdProperty = thresholdProperty;\n    this.trackUsage = trackUsage;\n  }\n\n  public synchronized Method getMethod(Class<?> clz) throws NoSuchMethodException {\n    if (executable == null) {\n      executable = trackUsage ? clz.getMethod(method, MemoryUsage.class) : clz.getMethod(method);\n    }\n    return executable;\n  }\n\n  public void invoke(Class<?> clz, Object... args)\n      throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {\n    getMethod(clz).invoke(clz, null, args);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/handlers/TimerHandler.java",
    "content": "package org.openjdk.btrace.core.handlers;\n\nimport java.lang.reflect.Method;\n\npublic final class TimerHandler {\n  public final String method;\n  public final long period;\n  public final String periodArg;\n\n  public TimerHandler(String method, long period, String periodArg) {\n    this.method = method;\n    this.period = period;\n    this.periodArg = periodArg;\n  }\n\n  public Method getMethod(Class<?> clz) throws NoSuchMethodException {\n    return clz.getMethod(method);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/jfr/JfrEvent.java",
    "content": "package org.openjdk.btrace.core.jfr;\n\n@SuppressWarnings(\"UnusedReturnValue\")\npublic abstract class JfrEvent {\n  public static final class Template {\n    public static final class Field {\n      private final String name;\n      private final String type;\n      private final String label;\n      private final String description;\n      private final String specificationName;\n      private final String specificationValue;\n\n      public Field(\n          String name,\n          String type,\n          String label,\n          String description,\n          String specificationName,\n          String specificationValue) {\n        this.name = name;\n        this.type = type;\n        this.label = label;\n        this.description = description;\n        this.specificationName = specificationName;\n        this.specificationValue = specificationValue;\n      }\n\n      public String getName() {\n        return name;\n      }\n\n      public String getType() {\n        return type;\n      }\n\n      public String getLabel() {\n        return label;\n      }\n\n      public String getDescription() {\n        return description;\n      }\n\n      public String getSpecificationName() {\n        return specificationName;\n      }\n\n      public String getSpecificationValue() {\n        return specificationValue;\n      }\n    }\n\n    private final String owner;\n    private final String name;\n    private final String label;\n    private final String description;\n    private final String[] category;\n    private final Field[] fields;\n    private final boolean stacktrace;\n    private final String period;\n    private final String periodicHandler;\n\n    public Template(\n        String owner,\n        String name,\n        String label,\n        String description,\n        String[] category,\n        Field[] fields,\n        boolean stacktrace,\n        String period,\n        String periodicHandler) {\n      this.owner = owner;\n      this.name = name;\n      this.label = label;\n      this.description = description;\n      this.category = category;\n      this.fields = fields;\n      this.stacktrace = stacktrace;\n      this.period = period;\n      this.periodicHandler = periodicHandler;\n    }\n\n    public String getOwner() {\n      return owner;\n    }\n\n    public String getName() {\n      return name;\n    }\n\n    public String getLabel() {\n      return label;\n    }\n\n    public String getDescription() {\n      return description;\n    }\n\n    public String[] getCategory() {\n      return category;\n    }\n\n    public Field[] getFields() {\n      return fields;\n    }\n\n    public boolean isStacktrace() {\n      return stacktrace;\n    }\n\n    public String getPeriod() {\n      return period;\n    }\n\n    public String getPeriodicHandler() {\n      return periodicHandler;\n    }\n  }\n\n  public interface Factory {\n    JfrEvent newEvent();\n  }\n\n  public static final JfrEvent EMPTY =\n      new JfrEvent() {\n        @Override\n        public JfrEvent withValue(String fieldName, byte value) {\n          return this;\n        }\n\n        @Override\n        public JfrEvent withValue(String fieldName, boolean value) {\n          return this;\n        }\n\n        @Override\n        public JfrEvent withValue(String fieldName, char value) {\n          return this;\n        }\n\n        @Override\n        public JfrEvent withValue(String fieldName, short value) {\n          return this;\n        }\n\n        @Override\n        public JfrEvent withValue(String fieldName, int value) {\n          return this;\n        }\n\n        @Override\n        public JfrEvent withValue(String fieldName, float value) {\n          return this;\n        }\n\n        @Override\n        public JfrEvent withValue(String fieldName, long value) {\n          return this;\n        }\n\n        @Override\n        public JfrEvent withValue(String fieldName, double value) {\n          return this;\n        }\n\n        @Override\n        public JfrEvent withValue(String fieldName, String value) {\n          return this;\n        }\n\n        @Override\n        public void commit() {}\n\n        @Override\n        public boolean shouldCommit() {\n          return false;\n        }\n\n        @Override\n        public void begin() {}\n\n        @Override\n        public void end() {}\n      };\n\n  public abstract JfrEvent withValue(String fieldName, byte value);\n\n  public abstract JfrEvent withValue(String fieldName, boolean value);\n\n  public abstract JfrEvent withValue(String fieldName, char value);\n\n  public abstract JfrEvent withValue(String fieldName, short value);\n\n  public abstract JfrEvent withValue(String fieldName, int value);\n\n  public abstract JfrEvent withValue(String fieldName, float value);\n\n  public abstract JfrEvent withValue(String fieldName, long value);\n\n  public abstract JfrEvent withValue(String fieldName, double value);\n\n  public abstract JfrEvent withValue(String fieldName, String value);\n\n  public abstract void commit();\n\n  public abstract boolean shouldCommit();\n\n  public abstract void begin();\n\n  public abstract void end();\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/types/AnyType.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.types;\n\n/**\n * This interface type is used in BTrace programs to tell that any reference type [object or array]\n * is allowed in the place where it is used. We use that for method signature matching when\n * signature needs to be specified loosely. Note that we don't want to use java.lang.Object -\n * because user may want to match java.lang.Object exactly.\n *\n * @author A. Sundararajan\n */\npublic interface AnyType {\n  AnyType VOID = new AnyType() {};\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/types/BTraceCollection.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.types;\n\nimport java.util.Collection;\n\n/**\n * Marker interface for BTrace defined collections\n *\n * @author Jaroslav Bachorik\n */\npublic interface BTraceCollection<T> extends Collection<T> {}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/types/BTraceDeque.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.types;\n\nimport java.util.ArrayDeque;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.Iterator;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic class BTraceDeque<V> implements Deque<V>, BTraceCollection<V>, Cloneable {\n  private final Deque<V> delegate;\n\n  public BTraceDeque(Deque<V> delegate) {\n    this.delegate = delegate;\n  }\n\n  @Override\n  public synchronized String toString() {\n    return delegate.toString();\n  }\n\n  @Override\n  public synchronized <T> T[] toArray(T[] a) {\n    return delegate.toArray(a);\n  }\n\n  @Override\n  public synchronized Object[] toArray() {\n    return delegate.toArray();\n  }\n\n  @Override\n  public synchronized boolean retainAll(Collection<?> c) {\n    return delegate.retainAll(c);\n  }\n\n  @Override\n  public synchronized boolean removeAll(Collection<?> c) {\n    return delegate.removeAll(c);\n  }\n\n  @Override\n  public synchronized boolean isEmpty() {\n    return delegate.isEmpty();\n  }\n\n  @Override\n  public synchronized boolean containsAll(Collection<?> c) {\n    return delegate.containsAll(c);\n  }\n\n  @Override\n  public synchronized void clear() {\n    delegate.clear();\n  }\n\n  @Override\n  public synchronized boolean addAll(Collection<? extends V> c) {\n    return delegate.addAll(c);\n  }\n\n  @Override\n  public synchronized int size() {\n    return delegate.size();\n  }\n\n  @Override\n  public synchronized boolean removeLastOccurrence(Object o) {\n    return delegate.removeLastOccurrence(o);\n  }\n\n  @Override\n  public synchronized V removeLast() {\n    return delegate.removeLast();\n  }\n\n  @Override\n  public synchronized boolean removeFirstOccurrence(Object o) {\n    return delegate.removeFirstOccurrence(o);\n  }\n\n  @Override\n  public synchronized V removeFirst() {\n    return delegate.removeFirst();\n  }\n\n  @Override\n  public synchronized boolean remove(Object o) {\n    return delegate.remove(o);\n  }\n\n  @Override\n  public synchronized V remove() {\n    return delegate.remove();\n  }\n\n  @Override\n  public synchronized void push(V e) {\n    delegate.push(e);\n  }\n\n  @Override\n  public synchronized V pop() {\n    return delegate.pop();\n  }\n\n  @Override\n  public synchronized V pollLast() {\n    return delegate.pollLast();\n  }\n\n  @Override\n  public synchronized V pollFirst() {\n    return delegate.pollFirst();\n  }\n\n  @Override\n  public synchronized V poll() {\n    return delegate.poll();\n  }\n\n  @Override\n  public synchronized V peekLast() {\n    return delegate.peekLast();\n  }\n\n  @Override\n  public synchronized V peekFirst() {\n    return delegate.peekFirst();\n  }\n\n  @Override\n  public synchronized V peek() {\n    return delegate.peek();\n  }\n\n  @Override\n  public synchronized boolean offerLast(V e) {\n    return delegate.offerLast(e);\n  }\n\n  @Override\n  public synchronized boolean offerFirst(V e) {\n    return delegate.offerFirst(e);\n  }\n\n  @Override\n  public synchronized boolean offer(V e) {\n    return delegate.offer(e);\n  }\n\n  @Override\n  public synchronized Iterator<V> iterator() {\n    return delegate.iterator();\n  }\n\n  @Override\n  public synchronized V getLast() {\n    return delegate.getLast();\n  }\n\n  @Override\n  public synchronized V getFirst() {\n    return delegate.getFirst();\n  }\n\n  @Override\n  public synchronized V element() {\n    return delegate.element();\n  }\n\n  @Override\n  public synchronized Iterator<V> descendingIterator() {\n    return delegate.descendingIterator();\n  }\n\n  @Override\n  public synchronized boolean contains(Object o) {\n    return delegate.contains(o);\n  }\n\n  @Override\n  public synchronized void addLast(V e) {\n    delegate.addLast(e);\n  }\n\n  @Override\n  public synchronized void addFirst(V e) {\n    delegate.addFirst(e);\n  }\n\n  @Override\n  public synchronized boolean add(V e) {\n    return delegate.add(e);\n  }\n\n  @Override\n  public synchronized int hashCode() {\n    return delegate.hashCode();\n  }\n\n  @Override\n  public synchronized boolean equals(Object obj) {\n    return delegate.equals(obj);\n  }\n\n  @SuppressWarnings({\"RedundantThrows\", \"MethodDoesntCallSuperMethod\"})\n  @Override\n  protected Object clone() throws CloneNotSupportedException {\n    return new BTraceDeque<>(new ArrayDeque<>());\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/core/types/BTraceMap.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.core.types;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.WeakHashMap;\n\n/**\n * Instances of this class are used to store aggregate tracing data in BTrace.\n *\n * @author A. Sundararajan\n */\npublic final class BTraceMap<K, V> implements Map<K, V>, Cloneable {\n  // private int numItems;\n  private final Map<K, V> m;\n  private final boolean isWeak;\n  private transient Set<K> keySet = null;\n  private transient Set<Map.Entry<K, V>> entrySet = null;\n  private transient Collection<V> values = null;\n\n  public BTraceMap(Map<K, V> m) {\n    if (m == null) {\n      throw new NullPointerException();\n    }\n    this.m = m;\n    isWeak = (m instanceof WeakHashMap);\n  }\n\n  @Override\n  public synchronized int size() {\n    return m.size();\n  }\n\n  @Override\n  public synchronized boolean isEmpty() {\n    return m.isEmpty();\n  }\n\n  @Override\n  public synchronized boolean containsKey(Object key) {\n    return m.containsKey(key);\n  }\n\n  @Override\n  public synchronized boolean containsValue(Object value) {\n    return m.containsValue(value);\n  }\n\n  @Override\n  public synchronized V get(Object key) {\n    return m.get(key);\n  }\n\n  @Override\n  public synchronized V put(K key, V value) {\n    return m.put(key, value);\n  }\n\n  @Override\n  public synchronized V remove(Object key) {\n    return m.remove(key);\n  }\n\n  @Override\n  public synchronized void putAll(Map<? extends K, ? extends V> map) {\n    m.putAll(map);\n  }\n\n  @Override\n  public synchronized void clear() {\n    m.clear();\n  }\n\n  @Override\n  public synchronized Set<K> keySet() {\n    if (keySet == null) {\n      keySet = m.keySet();\n    }\n    return keySet;\n  }\n\n  @Override\n  public synchronized Set<Map.Entry<K, V>> entrySet() {\n    if (entrySet == null) {\n      entrySet = m.entrySet();\n    }\n    return entrySet;\n  }\n\n  @Override\n  public synchronized Collection<V> values() {\n    if (values == null) {\n      values = m.values();\n    }\n    return values;\n  }\n\n  @Override\n  public synchronized boolean equals(Object o) {\n    return m.equals(o);\n  }\n\n  @Override\n  public synchronized int hashCode() {\n    return m.hashCode();\n  }\n\n  @Override\n  public synchronized String toString() {\n    return m.toString();\n  }\n\n  @SuppressWarnings({\"RedundantThrows\", \"MethodDoesntCallSuperMethod\"})\n  @Override\n  protected Object clone() throws CloneNotSupportedException {\n    return new BTraceMap<>(isWeak ? new WeakHashMap<>() : new HashMap<>());\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/runtime/BTraceRuntimeAccess.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage org.openjdk.btrace.runtime;\n\nimport org.openjdk.btrace.core.BTraceRuntimeBridge;\nimport org.openjdk.btrace.core.extensions.ExtensionContext;\nimport org.openjdk.btrace.core.handlers.ErrorHandler;\nimport org.openjdk.btrace.core.handlers.EventHandler;\nimport org.openjdk.btrace.core.handlers.ExitHandler;\nimport org.openjdk.btrace.core.handlers.LowMemoryHandler;\nimport org.openjdk.btrace.core.handlers.TimerHandler;\n\n/**\n * Bootstrap-visible runtime access shim.\n */\npublic final class BTraceRuntimeAccess {\n  private static volatile Delegate delegate;\n\n  // for testing purposes; needs to be non-final\n  private static volatile boolean uniqueClientClassNames = true;\n\n  private BTraceRuntimeAccess() {}\n\n  public static void install(Delegate delegate) {\n    BTraceRuntimeAccess.delegate = delegate;\n  }\n\n  public static boolean isUniqueClientClassNames() {\n    return uniqueClientClassNames;\n  }\n\n  public static boolean enter(BTraceRuntimeBridge currentRt) {\n    Delegate current = delegate;\n    return current != null && current.enter(currentRt);\n  }\n\n  public static void leave() {\n    Delegate current = delegate;\n    if (current != null) {\n      current.leave();\n    }\n  }\n\n  public static BTraceRuntimeBridge forClass(\n      Class cl,\n      TimerHandler[] tHandlers,\n      EventHandler[] evHandlers,\n      ErrorHandler[] errHandlers,\n      ExitHandler[] eHandlers,\n      LowMemoryHandler[] lmHandlers) {\n    Delegate current = delegate;\n    return current != null\n        ? current.forClass(cl, tHandlers, evHandlers, errHandlers, eHandlers, lmHandlers)\n        : null;\n  }\n\n  public static ThreadLocal newThreadLocal(Object initValue) {\n    Delegate current = delegate;\n    return current != null ? current.newThreadLocal(initValue) : ThreadLocal.withInitial(() -> initValue);\n  }\n\n  public static String getClientName(String forClassName) {\n    Delegate current = delegate;\n    return current != null ? current.getClientName(forClassName) : forClassName;\n  }\n\n  public static ExtensionContext currentContext() {\n    Delegate current = delegate;\n    return current != null ? current.currentContext() : null;\n  }\n\n  public interface Delegate {\n    boolean enter(BTraceRuntimeBridge currentRt);\n\n    void leave();\n\n    BTraceRuntimeBridge forClass(\n        Class cl,\n        TimerHandler[] tHandlers,\n        EventHandler[] evHandlers,\n        ErrorHandler[] errHandlers,\n        ExitHandler[] eHandlers,\n        LowMemoryHandler[] lmHandlers);\n\n    ThreadLocal newThreadLocal(Object initValue);\n\n    String getClientName(String forClassName);\n\n    ExtensionContext currentContext();\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/java/org/openjdk/btrace/runtime/LinkingFlag.java",
    "content": "package org.openjdk.btrace.runtime;\n\npublic final class LinkingFlag {\n  private static final ThreadLocal<Integer> linking = new ThreadLocal<>();\n\n  public static int guardLinking() {\n    Integer current = linking.get();\n    current = current == null ? 0 : current;\n    linking.set(current + 1);\n    return current;\n  }\n\n  public static int get() {\n    Integer current = linking.get();\n    return current == null ? 0 : current;\n  }\n\n  public static void reset() {\n    Integer current = linking.get();\n    current = current == null ? 0 : current;\n    linking.set(current > 0 ? current - 1 : 0);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/main/resources/org/openjdk/btrace/core/annotations/jaxb.index",
    "content": "Kind\nWhere\n"
  },
  {
    "path": "btrace-core/src/main/resources/org/openjdk/btrace/core/messages.properties",
    "content": "# BTrace \"compile time\" and runtime error messages.\nreturn.type.should.be.void=btrace probe methods must return void\nbtrace.program.should.be.class=btrace program must be a class (not interface or enum)\nno.complex.unsafe.value=@BTrace.trusted|unsafe value should be only a plain boolean\nnot.a.btrace.program=@BTrace annotation is missing\nno.outer.class=btrace class should not be a local class\nno.asserts=asserts are not allowed\nno.catch=catching exception is not allowed\nno.do.while=do..while loops are not allowed\nno.enhanced.for=enhanced for statements are not allowed\nno.loops=loops (backward jumps) are not allowed\nno.for.loop=for loops are not allowed\nno.array.creation=array creation is not allowed\nno.new.object=object creation is not allowed; construct via a service-provided builder or factory and pass the result to the service\nno.synchronized.blocks=synchronized blocks are not allowed\nno.synchronized.methods=probe action methods should not be synchronized\nno.throw=throwing exception is not allowed\nno.try=try .. catch .. finally blocks are not allowed\nno.while.loop=while loops are not allowed\nno.other=\"other\" statement(s) are not allowed\nexecution.loop.danger=execution of btrace program may lead to endless loop which is not allowed\nmethod.should.be.public=btrace methods should be public\nclass.should.be.public=btrace class should be public\nno.static.method=static methods are not allowed (using BTrace short syntax)\nno.instance.method=instance methods are not allowed\nno.method.calls=method calls are not allowed - only BTraceUtils and calls on injected services or objects returned from services are allowed\nno.assignment=side-effects to probed program are not allowed\nno.nested.class=nested and inner classes are not allowed\nno.local.class=local classes are not allowed\nno.static.variables=static variables are not allowed (using BTrace short syntax)\nno.instance.variables=instance variables are not allowed\nobject.superclass.required=btrace class should extend java.lang.Object\nno.interface.implementation=btrace class can not implement interfaces\nno.class.literals=class literals are not allowed\nself.desc.invalid=@Self annotation applicable only for Kind.ENTRY and Kind.RETURN\nprobemethod.desc.invalid=@ProbeMethod annotation applicable only for Kind.ENTRY, Kind.RETURN and Kind.CALL\nprobeclass.desc.invalid=@ProbeClassName annotation applicable only for Kind.ENTRY, Kind.RETURN and Kind.CALL\nreturn.desc.invalid=@Return annotation applicable only for Kind.RETURN\nduration.desc.invalid=@Duration annotation applicable only for Kind.RETURN and Kind.ERROR\ntarget-method.desc.invalid=@TargetMethodOrField annotation applicable only for Kind.CALL, Kind.FIELD_GET, Kind.FIELD_SET, Kind.ARRAY_GET and Kind.ARRAY_SET\ntarget-instance.desc.invalid=@TargetInstance annotation applicable only for Kind.CALL, Kind.FIELD_GET, Kind.FIELD_SET, Kind.ARRAY_GET, Kind.ARRAY_SET, Kind.INSTANCEOF, Kind.CHECKCAST, Kind.ERROR, Kind.THROW, Kind.CATCH, Kind.SYNC_ENTRY or Kind.SYNC_EXIT\nonexit.invalid=@OnExit annotation applicable only to methods with signature (int)void\nonerror.invalid=@OnError annotation applicable only to methods with signature (java.lang.Throwable)void\nmultiple.param.annotation=Multiple parameters annotated by the same annotation are not allowed\nsampler.invalid.location=@Sampled annotation supported only for @OnMethod annotated classes with Kind of [ENTRY, RETURN, ERROR, CALL]\nmissing.injected=Service fields must be annotated by @Injected\ninjected.no.initializer=Injected fields must not use initializer\ninvalid.injected.service=Injected type is not declared as an extension service\nmissing.event=Event template fields must be annotated by either @Event or @PeriodicEvent\nevent.nonpublic.handler=Periodic event handler must be public\nevent.invalid.handler=Invalid periodic event handler specified - the handler method must take exactly one parameter of JfrEvent type\nagent.no.instance.variables=instance variables are not allowed\nagent.unsafe.not.allowed=Trusted mode, requested by the script, not allowed\njfr.event.invalid.field=Invalid JFR event field name\npermission.missing=extension requires permission that is not granted; grant it via the agent (--grant=...) or extension configuration\nremote.commands.help=\\\n  BTrace remote commands:\\n \\\n  - event <name>  : Send an event with an optional name\\n \\\n  - exit          : Terminate the BTrace probe\n\n# usage messages\nbtracec.usage=\\\n  Usage: btracec <options> <btrace source files>\\n\\\n  where possible options include:\\n  \\\n    -classpath <path> Specify where to find user class files and annotation processors\\n  \\\n    -cp <path>        Specify where to find user class files and annotation processors\\n  \\\n    -I <path>         Specify where to find include files\\n  \\\n    -d <directory>    Specify where to place generated class files\\n  \\\n    -nopack           Do not produce packed probes. Useful when targeting pre 1.3.10 versions.\\n  \\\n    -packext          File extension for script packs (default '.class'). Valid only if '-nopack' is not specified.\\n  \\\n    -trusted          Enable trusted script (eg. no checks)\nbtrace.usage=\\\n  Usage: btrace <options> <pid> <btrace source or .class file> <btrace arguments>\\n\\\n  where possible options include:\\n  \\\n    --version             Show the version\\n  \\\n    -v                    Run in verbose mode\\n  \\\n    -l                    List all locally attachable JVMs\\n  \\\n    -lp                   List active probes in the given JVM\\n  \\\n                    \\t\\t\\tExpects PID or app name as the follow-up argument\\n  \\\n                    \\t\\t\\tAll other options are discarded\\n  \\\n    -le                   List failed extensions in the given JVM\\n  \\\n                    \\t\\t\\tExpects PID or app name as the follow-up argument\\n  \\\n                    \\t\\t\\tAll other options are discarded\\n  \\\n    -r <probe id>         Reconnect to an active disconnected probe\\n  \\\n                    \\t\\t\\tExpects PID or app name as the follow-up argument\\n  \\\n                    \\t\\t\\tAll other options are discarded\\n  \\\n    -r help               Show help on the remote commands\\n \\\n    -o <file>             The path to store the probe output (will disable showing the output in console)\\n  \\\n    -u                    Run in trusted mode\\n  \\\n    -d <path>             Dump the instrumented classes to the specified path\\n  \\\n    -pd <path>            The search path for the probe XML descriptors\\n  \\\n    -classpath <path>     Specify where to find user class files and annotation processors\\n  \\\n    -cp <path>            Specify where to find user class files and annotation processors\\n  \\\n    -I <path>             Specify where to find include files\\n  \\\n    -p <port>             Specify port to which the btrace agent listens for clients\\n  \\\n    -statsd <host[:port]> Specify the statsd server, if any\\n  \\\n    -n <oneliner>         Execute a BTrace oneliner expression\\n  \\\n    --oneliner <expr>       Example: -n 'javax.swing.*::* @entry { print method }'\\n  \\\n                    \\t\\t\\tSupports @entry, @return, @error locations and\\n  \\\n                    \\t\\t\\tprint, count, time, stack actions with filters\\n  \\\n    --agent-jar <path>    Specify path to btrace-agent.jar (overrides auto-discovery)\\n  \\\n    --boot-jar <path>     Specify path to btrace-boot.jar (overrides auto-discovery)\\n  \\\n    --extract-agent [dir] Extract embedded agent JARs to directory (default: current dir)\\n  \\\n    --grant <perms>       Grant specific permissions (comma-separated)\\n  \\\n                    \\t\\t\\tExample: --grant=NETWORK,THREADS\\n  \\\n    --deny <perms>        Deny specific permissions (comma-separated)\\n  \\\n    --grantAll            Grant all permissions (use with caution)\\n  \\\n    -x                    Run unattended\\n  \\\n                    \\t\\t\\tDeploy the given probe and disconnect\\n\\n  \\\n  Permissions: MESSAGING, AGGREGATION, JFR_EVENTS, PROFILING (default),\\n  \\\n               FILE_READ, SYSTEM_PROPS, THREAD_INFO, MEMORY_INFO (standard),\\n  \\\n               FILE_WRITE, NETWORK, THREADS, NATIVE, EXEC, REFLECTION,\\n  \\\n               CLASSLOADER, UNLIMITED_MEMORY (privileged)\nbtrace.agent.usage=\\\n  Usage: java -javaagent:java-agent.jar=<arguments> <main class> <application arguments>\\n\\\n  where arguments is comma separated name=value pairs. Argument names include:\\n  \\\n    bootClassPath    boot classpath to be used\\n  \\\n    systemClassPath  system classpath to be used\\n  \\\n    debug            boolean flag to specify debug mode\\n  \\\n    trusted          boolean flag to enable trusted mode\\n  \\\n    dumpClasses      boolean flag to specify whether to dump .classes for instrumented classes\\n  \\\n    dumpDir          directory where instrumented .class files are saved\\n  \\\n    help             print this help message\\n  \\\n    noServer         boolean flag to specify whether to start btrace server or not\\n  \\\n    port             btrace agent server port\\n  \\\n    statsd           statsd server, if any (format <host[:port]>)\\n  \\\n    allowExtensions  comma-separated list of extension IDs explicitly allowed to link implementations\\n  \\\n    denyExtensions   comma-separated list of extension IDs explicitly denied from linking implementations\\n  \\\n    allowPrivileged allow all privileged extensions to link implementations (true/false)\\n  \\\n    probeDescPath    directories where @OnProbe mapping descriptor XML files are searched\\n  \\\n    stdout           redirect the btrace output to stdout instead of writing it to an arbitrary file (true/false)\\n  \\\n    scriptdir        the path to a directory containing scripts to be run at the agent startup\\n  \\\n    scriptOutputFile the path to a file the btrace agent will store its output\\n  \\\n    grant            comma-separated list of permissions to grant (e.g. grant=NETWORK,THREADS)\\n  \\\n    deny             comma-separated list of permissions to deny (e.g. deny=EXEC,NATIVE)\\n  \\\n    grantAll         grant all permissions (true/false) - use with caution\\n   \\\n    script           comma separated list of compiled tracing scripts to be run at the agent startup; *MUST* be the last argument in the list\\n\\n  \\\n  Permissions:\\n  \\\n    Default (always granted): MESSAGING, AGGREGATION, JFR_EVENTS, PROFILING\\n  \\\n    Standard (granted unless denied): FILE_READ, SYSTEM_PROPS, THREAD_INFO, MEMORY_INFO\\n  \\\n    Privileged (require explicit grant): FILE_WRITE, NETWORK, THREADS, NATIVE, EXEC,\\n  \\\n                                         REFLECTION, CLASSLOADER, UNLIMITED_MEMORY\nbtrace.version=BTrace v.@btrace.version@ (@hash@)\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/CircularBufferTest.java",
    "content": "package org.openjdk.btrace.core;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport org.junit.jupiter.api.Test;\n\npublic class CircularBufferTest {\n\n  @Test\n  public void testAddOverflow() {\n    CircularBuffer<Integer> cb = new CircularBuffer<>(3);\n    cb.add(1);\n    cb.add(2);\n    cb.add(3);\n    cb.add(4);\n\n    assertEquals(3, cb.getLength());\n    final List<Integer> elements = new ArrayList<>();\n    cb.forEach(\n        new Function<Integer, Boolean>() {\n          @Override\n          public Boolean apply(Integer value) {\n            elements.add(value);\n            return true;\n          }\n        });\n\n    assertEquals(0, cb.getLength());\n    assertEquals(Arrays.asList(2, 3, 4), elements);\n  }\n\n  @Test\n  public void testAddOverflowSeveral() {\n    CircularBuffer<Integer> cb = new CircularBuffer<>(2);\n    cb.add(1);\n    cb.add(2);\n    cb.add(3);\n    cb.add(4);\n    cb.add(5);\n    cb.add(6);\n    cb.add(7);\n\n    assertEquals(2, cb.getLength());\n    final List<Integer> elements = new ArrayList<>();\n    cb.forEach(\n        new Function<Integer, Boolean>() {\n          @Override\n          public Boolean apply(Integer value) {\n            elements.add(value);\n            return true;\n          }\n        });\n    assertEquals(0, cb.getLength());\n\n    assertEquals(Arrays.asList(6, 7), elements);\n  }\n\n  @Test\n  public void testAdd() {\n    CircularBuffer<Integer> cb = new CircularBuffer<>(2);\n\n    cb.add(1);\n    assertEquals(1, cb.getLength());\n    final List<Integer> elements = new ArrayList<>();\n    cb.forEach(\n        new Function<Integer, Boolean>() {\n          @Override\n          public Boolean apply(Integer value) {\n            elements.add(value);\n            return true;\n          }\n        });\n    assertEquals(0, cb.getLength());\n    assertEquals(Arrays.asList(1), elements);\n  }\n\n  @Test\n  public void testAddFull() {\n    CircularBuffer<Integer> cb = new CircularBuffer<>(2);\n\n    cb.add(1);\n    cb.add(2);\n    assertEquals(2, cb.getLength());\n    final List<Integer> elements = new ArrayList<>();\n    cb.forEach(\n        new Function<Integer, Boolean>() {\n          @Override\n          public Boolean apply(Integer value) {\n            elements.add(value);\n            return true;\n          }\n        });\n    assertEquals(0, cb.getLength());\n    assertEquals(Arrays.asList(1, 2), elements);\n  }\n\n  @Test\n  public void testEmpty() {\n    CircularBuffer<Integer> cb = new CircularBuffer<>(2);\n\n    final List<Integer> elements = new ArrayList<>();\n    cb.forEach(\n        new Function<Integer, Boolean>() {\n          @Override\n          public Boolean apply(Integer value) {\n            elements.add(value);\n            return true;\n          }\n        });\n    assertTrue(elements.isEmpty());\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/MethodIDTest.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n */\npackage org.openjdk.btrace.core;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.lang.reflect.Field;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass MethodIDTest {\n\n  @BeforeEach\n  void resetState() throws Exception {\n    // Reset the static fields for isolation between tests\n    Field lastFld = MethodID.class.getDeclaredField(\"lastMethodId\");\n    Field mapFld = MethodID.class.getDeclaredField(\"methodIds\");\n\n    lastFld.setAccessible(true);\n    mapFld.setAccessible(true);\n\n    AtomicInteger last = (AtomicInteger) lastFld.get(null);\n    @SuppressWarnings(\"unchecked\")\n    Map<String, Integer> map = (Map<String, Integer>) mapFld.get(null);\n\n    last.set(1);\n    map.clear();\n  }\n\n  @Test\n  void singleThreadedConsistency() {\n    int id1 = MethodID.getMethodId(\"A#foo#()V\");\n    int id2 = MethodID.getMethodId(\"A#foo#()V\");\n    int id3 = MethodID.getMethodId(\"A#bar#()V\");\n\n    assertEquals(id1, id2, \"Same tag should return same ID\");\n    assertNotEquals(id1, id3, \"Different tags should return different IDs\");\n  }\n\n  @Test\n  void concurrentGenerationHasNoDuplicates() throws Exception {\n    int threads = 10;\n    int idsPerThread = 1000;\n    ExecutorService pool = Executors.newFixedThreadPool(threads);\n    ConcurrentMap<Integer, String> reverse = new ConcurrentHashMap<>();\n    CountDownLatch start = new CountDownLatch(1);\n    CountDownLatch done = new CountDownLatch(threads);\n\n    for (int t = 0; t < threads; t++) {\n      final int idx = t;\n      pool.submit(\n          () -> {\n            try {\n              start.await();\n              for (int i = 0; i < idsPerThread; i++) {\n                String tag = \"C\" + idx + \"#m\" + i + \"#()V\";\n                int id = MethodID.getMethodId(tag);\n                String prev = reverse.putIfAbsent(id, tag);\n                if (prev != null && !prev.equals(tag)) {\n                  fail(\"Duplicate ID assigned to different tags: \" + id + \" => \" + prev + \" vs \" + tag);\n                }\n              }\n            } catch (InterruptedException e) {\n              Thread.currentThread().interrupt();\n              fail(e);\n            } finally {\n              done.countDown();\n            }\n          });\n    }\n\n    start.countDown();\n    assertTrue(done.await(30, TimeUnit.SECONDS), \"Tasks should complete timely\");\n    pool.shutdownNow();\n\n    // Ensure expected cardinality\n    assertEquals(threads * idsPerThread, reverse.size(), \"Every tag should map to a unique ID\");\n\n    // Re-check stability: calling again returns same id\n    Set<Integer> secondPass = new HashSet<>();\n    for (Map.Entry<Integer, String> e : reverse.entrySet()) {\n      int id = MethodID.getMethodId(e.getValue());\n      assertTrue(secondPass.add(id), \"IDs should still be unique on second pass\");\n    }\n    assertEquals(reverse.size(), secondPass.size());\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/PrefixMapTest.java",
    "content": "package org.openjdk.btrace.core;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport org.junit.jupiter.api.Test;\n\nclass PrefixMapTest {\n  @Test\n  void addAndContainsWorkWithDuplicates() {\n    PrefixMap pm = new PrefixMap();\n    pm.add(\"abc\");\n    pm.add(\"abc\"); // duplicate\n    pm.add(\"abcd\");\n\n    assertTrue(pm.contains(\"abc\"));\n    assertTrue(pm.contains(\"abcdef\"));\n    assertTrue(pm.contains(\"abcd\"));\n    assertFalse(pm.contains(\"ab\"));\n    assertFalse(pm.contains(\"abX\"));\n  }\n}\n\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/ReflectiveFieldAccessTest.java",
    "content": "package org.openjdk.btrace.core;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport org.junit.jupiter.api.Test;\n\nclass ReflectiveFieldAccessTest {\n\n  @Test\n  public void getIntTest() {\n    D a = new D();\n    RuntimeException exception =\n        assertThrows(RuntimeException.class, () -> BTraceUtils.Reflective.getInt(\"notExist\", a));\n    assertTrue(exception.getMessage().contains(\"notExist\"));\n  }\n\n  static class A {\n    int a;\n  }\n\n  static class B extends A {}\n\n  static class C extends A {}\n\n  static class D extends C {}\n}\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/InstrumentCommandTest.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.core.comm;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.ArgsMap;\n\n/**\n * Tests for InstrumentCommand defensive copying to prevent external modification of bytecode and\n * arguments.\n */\nclass InstrumentCommandTest {\n\n  @Test\n  void testConstructorWithArgsMapMakesDefensiveCopy() {\n    byte[] bytecode = {0x01, 0x02, 0x03};\n    ArgsMap args = new ArgsMap();\n    args.put(\"key1\", \"value1\");\n\n    InstrumentCommand cmd = new InstrumentCommand(bytecode, args);\n\n    // Modify the original bytecode array\n    bytecode[0] = (byte) 0xFF;\n\n    // Modify the original ArgsMap\n    args.put(\"key2\", \"value2\");\n\n    // Verify command's internal state was not affected\n    byte[] retrievedCode = cmd.getCode();\n    assertEquals(0x01, retrievedCode[0], \"Bytecode should not be affected by external modification\");\n\n    ArgsMap retrievedArgs = cmd.getArguments();\n    assertNull(retrievedArgs.get(\"key2\"), \"Args should not be affected by external modification\");\n    assertEquals(\"value1\", retrievedArgs.get(\"key1\"));\n  }\n\n  @Test\n  void testConstructorWithStringArrayArgs() {\n    byte[] bytecode = {0x01, 0x02, 0x03};\n    String[] args = {\"key1=value1\", \"key2=value2\"};\n\n    InstrumentCommand cmd = new InstrumentCommand(bytecode, args);\n\n    // Modify original bytecode\n    bytecode[0] = (byte) 0xFF;\n\n    // Verify bytecode is protected\n    assertEquals(0x01, cmd.getCode()[0]);\n\n    // Verify args were parsed correctly\n    assertEquals(\"value1\", cmd.getArguments().get(\"key1\"));\n    assertEquals(\"value2\", cmd.getArguments().get(\"key2\"));\n  }\n\n  @Test\n  void testConstructorWithMapArgs() {\n    byte[] bytecode = {0x01, 0x02, 0x03};\n    Map<String, String> argsMap = new HashMap<>();\n    argsMap.put(\"key1\", \"value1\");\n\n    InstrumentCommand cmd = new InstrumentCommand(bytecode, argsMap);\n\n    // Modify original bytecode and map\n    bytecode[0] = (byte) 0xFF;\n    argsMap.put(\"key2\", \"value2\");\n\n    // Verify command is protected\n    assertEquals(0x01, cmd.getCode()[0]);\n    assertNull(cmd.getArguments().get(\"key2\"));\n  }\n\n  @Test\n  void testGetCodeReturnsDefensiveCopy() {\n    byte[] bytecode = {0x01, 0x02, 0x03};\n    InstrumentCommand cmd = new InstrumentCommand(bytecode, new ArgsMap());\n\n    byte[] retrieved1 = cmd.getCode();\n    byte[] retrieved2 = cmd.getCode();\n\n    // Modify the returned array\n    retrieved1[0] = (byte) 0xFF;\n\n    // Verify original is unchanged\n    assertEquals(0x01, cmd.getCode()[0], \"getCode() should return a defensive copy\");\n\n    // Verify each call returns a new copy\n    assertNotSame(retrieved1, retrieved2, \"getCode() should return new copy each time\");\n    assertEquals(0x01, retrieved2[0], \"Second call should return unmodified bytecode\");\n  }\n\n  @Test\n  void testNullBytecode() {\n    InstrumentCommand cmd = new InstrumentCommand(null, new ArgsMap());\n\n    assertNull(cmd.getCode(), \"Null bytecode should remain null\");\n  }\n\n  @Test\n  void testNullArgs() {\n    byte[] bytecode = {0x01, 0x02, 0x03};\n    InstrumentCommand cmd = new InstrumentCommand(bytecode, (ArgsMap) null);\n\n    assertNull(cmd.getArguments(), \"Null args should remain null\");\n  }\n\n  @Test\n  void testEmptyBytecode() {\n    byte[] bytecode = {};\n    InstrumentCommand cmd = new InstrumentCommand(bytecode, new ArgsMap());\n\n    assertNotNull(cmd.getCode());\n    assertEquals(0, cmd.getCode().length);\n  }\n\n  @Test\n  void testEmptyArgs() {\n    byte[] bytecode = {0x01, 0x02, 0x03};\n    ArgsMap args = new ArgsMap();\n    InstrumentCommand cmd = new InstrumentCommand(bytecode, args);\n\n    assertNotNull(cmd.getArguments());\n    assertEquals(0, cmd.getArguments().size());\n  }\n\n  @Test\n  void testLargeBytecodeArray() {\n    byte[] bytecode = new byte[1024 * 1024]; // 1MB\n    for (int i = 0; i < bytecode.length; i++) {\n      bytecode[i] = (byte) (i % 256);\n    }\n\n    InstrumentCommand cmd = new InstrumentCommand(bytecode, new ArgsMap());\n\n    // Modify original\n    bytecode[1000] = (byte) 0xFF;\n\n    // Verify copy is independent\n    assertNotEquals((byte) 0xFF, cmd.getCode()[1000]);\n  }\n\n  @Test\n  void testMultipleArguments() {\n    byte[] bytecode = {0x01, 0x02, 0x03};\n    ArgsMap args = new ArgsMap();\n    args.put(\"arg1\", \"value1\");\n    args.put(\"arg2\", \"value2\");\n    args.put(\"arg3\", \"value3\");\n\n    InstrumentCommand cmd = new InstrumentCommand(bytecode, args);\n\n    // Modify original\n    args.put(\"arg4\", \"value4\");\n    args.put(\"arg1\", \"modified\");\n\n    // Verify command's args are unchanged\n    ArgsMap cmdArgs = cmd.getArguments();\n    assertEquals(3, cmdArgs.size());\n    assertEquals(\"value1\", cmdArgs.get(\"arg1\"));\n    assertEquals(\"value2\", cmdArgs.get(\"arg2\"));\n    assertEquals(\"value3\", cmdArgs.get(\"arg3\"));\n    assertNull(cmdArgs.get(\"arg4\"));\n  }\n}\n\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/JavaSerializationProtocolLeakTest.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n */\npackage org.openjdk.btrace.core.comm;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport org.junit.jupiter.api.Test;\n\nclass JavaSerializationProtocolLeakTest {\n\n  static class FailingInputStream extends InputStream {\n    @Override\n    public int read() throws IOException {\n      throw new IOException(\"boom\");\n    }\n  }\n\n  static class CloseTrackingOutputStream extends OutputStream {\n    final AtomicBoolean closed = new AtomicBoolean(false);\n\n    @Override\n    public void write(int b) throws IOException {\n      // accept anything\n    }\n\n    @Override\n    public void close() throws IOException {\n      closed.set(true);\n      super.close();\n    }\n  }\n\n  @Test\n  void constructorClosesOutputStreamOnInputInitFailure() {\n    InputStream failingIn = new FailingInputStream();\n    CloseTrackingOutputStream trackingOut = new CloseTrackingOutputStream();\n\n    IOException ex = assertThrows(IOException.class, () -> new JavaSerializationProtocol(failingIn, trackingOut));\n    assertTrue(trackingOut.closed.get(), \"Output stream should be closed when input init fails\");\n    assertEquals(\"boom\", ex.getMessage());\n  }\n}\n\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/ListProbesCommandConcurrencyTest.java",
    "content": "package org.openjdk.btrace.core.comm;\n\nimport static org.junit.jupiter.api.Assertions.assertDoesNotThrow;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.ObjectOutputStream;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport org.junit.jupiter.api.Test;\n\nclass ListProbesCommandConcurrencyTest {\n\n  @Test\n  void concurrentSetAndIterateDoesNotThrow() throws Exception {\n    ListProbesCommand cmd = new ListProbesCommand();\n\n    CountDownLatch start = new CountDownLatch(1);\n    CountDownLatch done = new CountDownLatch(2);\n\n    Runnable writer = () -> {\n      try {\n        start.await();\n        for (int r = 0; r < 500; r++) {\n          int size = (r % 10) + 1;\n          List<String> list = new ArrayList<>(size);\n          for (int i = 0; i < size; i++) {\n            list.add(\"probe-\" + r + '-' + i);\n          }\n          cmd.setProbes(list);\n        }\n      } catch (InterruptedException ignored) {\n        Thread.currentThread().interrupt();\n      } finally {\n        done.countDown();\n      }\n    };\n\n    Runnable reader = () -> {\n      try {\n        start.await();\n        for (int r = 0; r < 500; r++) {\n          // print()\n          StringWriter sw = new StringWriter();\n          PrintWriter pw = new PrintWriter(sw);\n          assertDoesNotThrow(() -> cmd.print(pw));\n\n          // write()\n          assertDoesNotThrow(\n              () -> {\n                ByteArrayOutputStream baos = new ByteArrayOutputStream();\n                try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {\n                  cmd.write(oos);\n                }\n              });\n        }\n      } catch (InterruptedException ignored) {\n        Thread.currentThread().interrupt();\n      } finally {\n        done.countDown();\n      }\n    };\n\n    new Thread(writer).start();\n    new Thread(reader).start();\n    start.countDown();\n\n    // Ensure both loops finished\n    done.await(10, TimeUnit.SECONDS);\n  }\n}\n\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/NullSafetyTest.java",
    "content": "/*\n * Tests for null safety in command print() methods to prevent NullPointerExceptions.\n */\npackage org.openjdk.btrace.core.comm;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.junit.jupiter.api.Test;\n\nclass NullSafetyTest {\n\n  @Test\n  void testErrorCommandPrintWithNullCause() {\n    ErrorCommand cmd = new ErrorCommand(null);\n    StringWriter sw = new StringWriter();\n    PrintWriter pw = new PrintWriter(sw);\n\n    assertDoesNotThrow(() -> cmd.print(pw));\n\n    String output = sw.toString();\n    assertTrue(output.contains(\"! ERROR\"));\n    assertTrue(output.contains(\"No exception information available\"));\n  }\n\n  @Test\n  void testGridDataCommandWithNullRow() {\n    List<Object[]> data = new ArrayList<>();\n    data.add(new Object[] {\"Row1\", 100});\n    data.add(null);\n    data.add(new Object[] {\"Row3\", 300});\n\n    GridDataCommand cmd = new GridDataCommand(\"TestGrid\", data);\n    StringWriter sw = new StringWriter();\n    PrintWriter pw = new PrintWriter(sw);\n\n    assertDoesNotThrow(() -> cmd.print(pw));\n    String output = sw.toString();\n    assertTrue(output.contains(\"Row1\"));\n    assertTrue(output.contains(\"Row3\"));\n  }\n\n  @Test\n  void testMessageCommandWithNullMessage() {\n    MessageCommand cmd = new MessageCommand((String) null);\n    StringWriter sw = new StringWriter();\n    PrintWriter pw = new PrintWriter(sw);\n\n    assertDoesNotThrow(() -> cmd.print(pw));\n  }\n}\n\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/ProtocolConfigTest.java",
    "content": "package org.openjdk.btrace.core.comm;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\n/** Tests for ProtocolConfig. */\npublic class ProtocolConfigTest {\n\n  @AfterEach\n  public void clearSystemProperties() {\n    System.clearProperty(\"btrace.comm.protocol\");\n    System.clearProperty(\"btrace.comm.autoNegotiate\");\n    System.clearProperty(\"btrace.comm.forceVersion\");\n  }\n\n  @Test\n  public void testDefaultConfig() {\n    ProtocolConfig config = ProtocolConfig.getDefault();\n\n    assertEquals(ProtocolVersion.V2, config.getVersion());\n    assertTrue(config.isAutoNegotiate());\n    assertFalse(config.isForceVersion());\n  }\n\n  @Test\n  public void testBuilderDefaultValues() {\n    ProtocolConfig config = ProtocolConfig.builder().build();\n\n    assertEquals(ProtocolVersion.V2, config.getVersion());\n    assertTrue(config.isAutoNegotiate());\n    assertFalse(config.isForceVersion());\n  }\n\n  @Test\n  public void testBuilderCustomVersion() {\n    ProtocolConfig config = ProtocolConfig.builder().version(ProtocolVersion.V1).build();\n\n    assertEquals(ProtocolVersion.V1, config.getVersion());\n    assertTrue(config.isAutoNegotiate());\n    assertFalse(config.isForceVersion());\n  }\n\n  @Test\n  public void testBuilderDisableAutoNegotiate() {\n    ProtocolConfig config = ProtocolConfig.builder().autoNegotiate(false).build();\n\n    assertEquals(ProtocolVersion.V2, config.getVersion());\n    assertFalse(config.isAutoNegotiate());\n    assertFalse(config.isForceVersion());\n  }\n\n  @Test\n  public void testBuilderForceVersion() {\n    ProtocolConfig config =\n        ProtocolConfig.builder()\n            .version(ProtocolVersion.V1)\n            .autoNegotiate(false)\n            .forceVersion(true)\n            .build();\n\n    assertEquals(ProtocolVersion.V1, config.getVersion());\n    assertFalse(config.isAutoNegotiate());\n    assertTrue(config.isForceVersion());\n  }\n\n  @Test\n  public void testBuilderInvalidConfiguration() {\n    // Cannot have both forceVersion and autoNegotiate enabled\n    assertThrows(\n        IllegalArgumentException.class,\n        () -> ProtocolConfig.builder().autoNegotiate(true).forceVersion(true).build());\n  }\n\n  @Test\n  public void testFromSystemPropertiesNoProperties() {\n    ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n\n    // Should return default config when no properties are set\n    assertEquals(ProtocolVersion.V2, config.getVersion());\n    assertTrue(config.isAutoNegotiate());\n    assertFalse(config.isForceVersion());\n  }\n\n  @Test\n  public void testFromSystemPropertiesProtocolV1() {\n    System.setProperty(\"btrace.comm.protocol\", \"v1\");\n    ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n\n    assertEquals(ProtocolVersion.V1, config.getVersion());\n    assertTrue(config.isAutoNegotiate());\n    assertFalse(config.isForceVersion());\n  }\n\n  @Test\n  public void testFromSystemPropertiesProtocolV2() {\n    System.setProperty(\"btrace.comm.protocol\", \"v2\");\n    ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n\n    assertEquals(ProtocolVersion.V2, config.getVersion());\n    assertTrue(config.isAutoNegotiate());\n  }\n\n  @Test\n  public void testFromSystemPropertiesProtocolNumeric() {\n    System.setProperty(\"btrace.comm.protocol\", \"1\");\n    ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n    assertEquals(ProtocolVersion.V1, config.getVersion());\n\n    System.setProperty(\"btrace.comm.protocol\", \"2\");\n    config = ProtocolConfig.fromSystemProperties();\n    assertEquals(ProtocolVersion.V2, config.getVersion());\n  }\n\n  @Test\n  public void testFromSystemPropertiesProtocolUppercase() {\n    System.setProperty(\"btrace.comm.protocol\", \"V1\");\n    ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n    assertEquals(ProtocolVersion.V1, config.getVersion());\n\n    System.setProperty(\"btrace.comm.protocol\", \"V2\");\n    config = ProtocolConfig.fromSystemProperties();\n    assertEquals(ProtocolVersion.V2, config.getVersion());\n  }\n\n  @Test\n  public void testFromSystemPropertiesInvalidProtocol() {\n    System.setProperty(\"btrace.comm.protocol\", \"invalid\");\n    assertThrows(IllegalArgumentException.class, () -> ProtocolConfig.fromSystemProperties());\n  }\n\n  @Test\n  public void testFromSystemPropertiesAutoNegotiate() {\n    System.setProperty(\"btrace.comm.autoNegotiate\", \"false\");\n    ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n\n    assertFalse(config.isAutoNegotiate());\n  }\n\n  @Test\n  public void testFromSystemPropertiesForceVersion() {\n    System.setProperty(\"btrace.comm.protocol\", \"v1\");\n    System.setProperty(\"btrace.comm.autoNegotiate\", \"false\");\n    System.setProperty(\"btrace.comm.forceVersion\", \"true\");\n    ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n\n    assertEquals(ProtocolVersion.V1, config.getVersion());\n    assertFalse(config.isAutoNegotiate());\n    assertTrue(config.isForceVersion());\n  }\n\n  @Test\n  public void testFromSystemPropertiesAllProperties() {\n    System.setProperty(\"btrace.comm.protocol\", \"v2\");\n    System.setProperty(\"btrace.comm.autoNegotiate\", \"true\");\n    System.setProperty(\"btrace.comm.forceVersion\", \"false\");\n    ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n\n    assertEquals(ProtocolVersion.V2, config.getVersion());\n    assertTrue(config.isAutoNegotiate());\n    assertFalse(config.isForceVersion());\n  }\n\n  @Test\n  public void testToString() {\n    ProtocolConfig config = ProtocolConfig.getDefault();\n    String str = config.toString();\n\n    assertTrue(str.contains(\"version=\"));\n    assertTrue(str.contains(\"autoNegotiate=\"));\n    assertTrue(str.contains(\"forceVersion=\"));\n  }\n\n  @Test\n  public void testBuilderChaining() {\n    ProtocolConfig config =\n        ProtocolConfig.builder()\n            .version(ProtocolVersion.V1)\n            .autoNegotiate(false)\n            .forceVersion(false)\n            .build();\n\n    assertEquals(ProtocolVersion.V1, config.getVersion());\n    assertFalse(config.isAutoNegotiate());\n    assertFalse(config.isForceVersion());\n  }\n\n  @Test\n  public void testMultipleBuilds() {\n    ProtocolConfig.Builder builder = ProtocolConfig.builder();\n\n    ProtocolConfig config1 = builder.version(ProtocolVersion.V1).build();\n    ProtocolConfig config2 = builder.version(ProtocolVersion.V2).build();\n\n    // Each build should create independent instances\n    assertNotSame(config1, config2);\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/ProtocolNegotiatorTest.java",
    "content": "package org.openjdk.btrace.core.comm;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PushbackInputStream;\nimport org.junit.jupiter.api.Test;\n\n/** Tests for ProtocolNegotiator and ProtocolVersion. */\npublic class ProtocolNegotiatorTest {\n\n  @Test\n  public void testProtocolVersionV1() {\n    assertEquals(1, ProtocolVersion.V1.getVersion());\n    assertFalse(ProtocolVersion.V1.hasMagicBytes());\n    assertEquals(0, ProtocolVersion.V1.getMagicBytes().length);\n  }\n\n  @Test\n  public void testProtocolVersionV2() {\n    assertEquals(2, ProtocolVersion.V2.getVersion());\n    assertTrue(ProtocolVersion.V2.hasMagicBytes());\n    byte[] magicBytes = ProtocolVersion.V2.getMagicBytes();\n    assertEquals(4, magicBytes.length);\n    assertEquals(0x42, magicBytes[0]); // 'B'\n    assertEquals(0x54, magicBytes[1]); // 'T'\n    assertEquals(0x52, magicBytes[2]); // 'R'\n    assertEquals(0x32, magicBytes[3]); // '2'\n  }\n\n  @Test\n  public void testProtocolVersionFromVersion() {\n    assertEquals(ProtocolVersion.V1, ProtocolVersion.fromVersion(1));\n    assertEquals(ProtocolVersion.V2, ProtocolVersion.fromVersion(2));\n\n    assertThrows(IllegalArgumentException.class, () -> ProtocolVersion.fromVersion(0));\n    assertThrows(IllegalArgumentException.class, () -> ProtocolVersion.fromVersion(3));\n    assertThrows(IllegalArgumentException.class, () -> ProtocolVersion.fromVersion(-1));\n  }\n\n  @Test\n  public void testProtocolVersionDetectFromPrefix() {\n    // V2 magic bytes\n    byte[] v2Prefix = {0x42, 0x54, 0x52, 0x32}; // \"BTR2\"\n    assertEquals(ProtocolVersion.V2, ProtocolVersion.detectFromPrefix(v2Prefix));\n\n    // V2 with extra bytes\n    byte[] v2PrefixExtra = {0x42, 0x54, 0x52, 0x32, 0x01, 0x02};\n    assertEquals(ProtocolVersion.V2, ProtocolVersion.detectFromPrefix(v2PrefixExtra));\n\n    // V1 (no magic bytes)\n    byte[] v1Prefix = {(byte) 0xAC, (byte) 0xED, 0x00, 0x05}; // Java serialization header\n    assertEquals(ProtocolVersion.V1, ProtocolVersion.detectFromPrefix(v1Prefix));\n\n    // Empty\n    assertEquals(ProtocolVersion.V1, ProtocolVersion.detectFromPrefix(new byte[0]));\n    assertEquals(ProtocolVersion.V1, ProtocolVersion.detectFromPrefix(null));\n\n    // Incomplete V2 magic\n    byte[] incomplete = {0x42, 0x54, 0x52}; // Only \"BTR\"\n    assertEquals(ProtocolVersion.V1, ProtocolVersion.detectFromPrefix(incomplete));\n\n    // Wrong magic bytes\n    byte[] wrong = {0x42, 0x54, 0x52, 0x31}; // \"BTR1\"\n    assertEquals(ProtocolVersion.V1, ProtocolVersion.detectFromPrefix(wrong));\n  }\n\n  @Test\n  public void testProtocolVersionGetDefault() {\n    assertEquals(ProtocolVersion.V2, ProtocolVersion.getDefault());\n  }\n\n  @Test\n  public void testNegotiatorDefaultConstructor() {\n    ProtocolNegotiator negotiator = new ProtocolNegotiator();\n    assertEquals(ProtocolVersion.V2, negotiator.getPreferredVersion());\n  }\n\n  @Test\n  public void testNegotiatorCustomVersion() {\n    ProtocolNegotiator negotiator = new ProtocolNegotiator(ProtocolVersion.V1);\n    assertEquals(ProtocolVersion.V1, negotiator.getPreferredVersion());\n  }\n\n  @Test\n  public void testNegotiateV2WithPushback() throws IOException {\n    byte[] v2Data = {0x42, 0x54, 0x52, 0x32, 0x01, 0x02, 0x03}; // \"BTR2\" + data\n    PushbackInputStream pis = new PushbackInputStream(new ByteArrayInputStream(v2Data), 4);\n\n    ProtocolNegotiator negotiator = new ProtocolNegotiator();\n    ProtocolVersion detected = negotiator.negotiate(pis);\n\n    assertEquals(ProtocolVersion.V2, detected);\n\n    // After negotiation, stream should be positioned after magic bytes\n    assertEquals(0x01, pis.read());\n    assertEquals(0x02, pis.read());\n    assertEquals(0x03, pis.read());\n  }\n\n  @Test\n  public void testNegotiateV1WithPushback() throws IOException {\n    byte[] v1Data = {(byte) 0xAC, (byte) 0xED, 0x00, 0x05}; // Java serialization header\n    PushbackInputStream pis = new PushbackInputStream(new ByteArrayInputStream(v1Data), 4);\n\n    ProtocolNegotiator negotiator = new ProtocolNegotiator();\n    ProtocolVersion detected = negotiator.negotiate(pis);\n\n    assertEquals(ProtocolVersion.V1, detected);\n\n    // After negotiation, stream should be reset to beginning (bytes pushed back)\n    assertEquals(0xAC, pis.read() & 0xFF);\n    assertEquals(0xED, pis.read() & 0xFF);\n    assertEquals(0x00, pis.read());\n    assertEquals(0x05, pis.read());\n  }\n\n  @Test\n  public void testNegotiateV2WithMark() throws IOException {\n    byte[] v2Data = {0x42, 0x54, 0x52, 0x32, 0x01, 0x02, 0x03}; // \"BTR2\" + data\n    ByteArrayInputStream bis = new ByteArrayInputStream(v2Data);\n\n    ProtocolNegotiator negotiator = new ProtocolNegotiator();\n    ProtocolVersion detected = negotiator.negotiate(bis);\n\n    assertEquals(ProtocolVersion.V2, detected);\n\n    // After negotiation, stream should be positioned after magic bytes\n    assertEquals(0x01, bis.read());\n    assertEquals(0x02, bis.read());\n    assertEquals(0x03, bis.read());\n  }\n\n  @Test\n  public void testNegotiateV1WithMark() throws IOException {\n    byte[] v1Data = {(byte) 0xAC, (byte) 0xED, 0x00, 0x05}; // Java serialization header\n    ByteArrayInputStream bis = new ByteArrayInputStream(v1Data);\n\n    ProtocolNegotiator negotiator = new ProtocolNegotiator();\n    ProtocolVersion detected = negotiator.negotiate(bis);\n\n    assertEquals(ProtocolVersion.V1, detected);\n\n    // After negotiation, stream should be reset to beginning\n    assertEquals(0xAC, bis.read() & 0xFF);\n    assertEquals(0xED, bis.read() & 0xFF);\n    assertEquals(0x00, bis.read());\n    assertEquals(0x05, bis.read());\n  }\n\n  @Test\n  public void testNegotiateEmptyStream() {\n    byte[] emptyData = {};\n    PushbackInputStream pis = new PushbackInputStream(new ByteArrayInputStream(emptyData), 4);\n\n    ProtocolNegotiator negotiator = new ProtocolNegotiator();\n    assertThrows(IOException.class, () -> negotiator.negotiate(pis));\n  }\n\n  @Test\n  public void testNegotiateUnsupportedStream() {\n    // Create a stream that doesn't support mark/reset or pushback\n    InputStream unsupported =\n        new InputStream() {\n          @Override\n          public int read() throws IOException {\n            return 0;\n          }\n\n          @Override\n          public boolean markSupported() {\n            return false;\n          }\n        };\n\n    ProtocolNegotiator negotiator = new ProtocolNegotiator();\n    assertThrows(IllegalArgumentException.class, () -> negotiator.negotiate(unsupported));\n  }\n\n  @Test\n  public void testCreateNegotiationStream() {\n    ByteArrayInputStream bis = new ByteArrayInputStream(new byte[10]);\n    PushbackInputStream pis = ProtocolNegotiator.createNegotiationStream(bis);\n\n    assertNotNull(pis);\n    assertTrue(pis instanceof PushbackInputStream);\n  }\n\n  @Test\n  public void testCreateNegotiationStreamAlreadyPushback() {\n    PushbackInputStream original = new PushbackInputStream(new ByteArrayInputStream(new byte[10]));\n    PushbackInputStream result = ProtocolNegotiator.createNegotiationStream(original);\n\n    assertSame(original, result);\n  }\n\n  @Test\n  public void testNegotiateMultipleV2Connections() throws IOException {\n    // Simulate multiple connections to ensure negotiation works repeatedly\n    for (int i = 0; i < 5; i++) {\n      byte[] v2Data = {0x42, 0x54, 0x52, 0x32, (byte) i};\n      PushbackInputStream pis = new PushbackInputStream(new ByteArrayInputStream(v2Data), 4);\n\n      ProtocolNegotiator negotiator = new ProtocolNegotiator();\n      ProtocolVersion detected = negotiator.negotiate(pis);\n\n      assertEquals(ProtocolVersion.V2, detected);\n      assertEquals(i, pis.read()); // Verify data after magic bytes\n    }\n  }\n\n  @Test\n  public void testNegotiateMultipleV1Connections() throws IOException {\n    // Simulate multiple connections to ensure negotiation works repeatedly\n    for (int i = 0; i < 5; i++) {\n      byte[] v1Data = {(byte) 0xAC, (byte) 0xED, 0x00, (byte) i};\n      PushbackInputStream pis = new PushbackInputStream(new ByteArrayInputStream(v1Data), 4);\n\n      ProtocolNegotiator negotiator = new ProtocolNegotiator();\n      ProtocolVersion detected = negotiator.negotiate(pis);\n\n      assertEquals(ProtocolVersion.V1, detected);\n      assertEquals(0xAC, pis.read() & 0xFF); // Verify pushed back\n    }\n  }\n\n  @Test\n  public void testProtocolVersionToString() {\n    assertTrue(ProtocolVersion.V1.toString().contains(\"version=1\"));\n    assertTrue(ProtocolVersion.V1.toString().contains(\"hasMagicBytes=false\"));\n\n    assertTrue(ProtocolVersion.V2.toString().contains(\"version=2\"));\n    assertTrue(ProtocolVersion.V2.toString().contains(\"hasMagicBytes=true\"));\n  }\n\n  @Test\n  public void testMagicBytesImmutable() {\n    // Ensure that modifying returned magic bytes doesn't affect the enum\n    byte[] magicBytes = ProtocolVersion.V2.getMagicBytes();\n    byte original = magicBytes[0];\n    magicBytes[0] = 0x00; // Try to modify\n\n    byte[] magicBytes2 = ProtocolVersion.V2.getMagicBytes();\n    assertEquals(original, magicBytes2[0]); // Should still be original value\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/TypeSafetyTest.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.core.comm;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\nimport org.junit.jupiter.api.Test;\n\n/**\n * Tests for type safety validation in Command deserialization.\n * These tests ensure that malformed or malicious data cannot cause\n * ClassCastException at runtime.\n */\nclass TypeSafetyTest {\n\n  @Test\n  void testNumberDataCommandValidNumber() throws Exception {\n    NumberDataCommand cmd = new NumberDataCommand(\"test\", 42);\n\n    // Serialize and deserialize\n    NumberDataCommand deserialized = roundTrip(cmd, NumberDataCommand.class);\n\n    assertEquals(\"test\", deserialized.name);\n    assertEquals(42, deserialized.getValue());\n  }\n\n  @Test\n  void testNumberDataCommandNullValue() throws Exception {\n    NumberDataCommand cmd = new NumberDataCommand(\"test\", null);\n\n    NumberDataCommand deserialized = roundTrip(cmd, NumberDataCommand.class);\n\n    assertEquals(\"test\", deserialized.name);\n    assertNull(deserialized.getValue());\n  }\n\n  @Test\n  void testNumberDataCommandRejectsInvalidType() throws Exception {\n    // Create a command and manually serialize with wrong type\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    ObjectOutputStream oos = new ObjectOutputStream(baos);\n\n    // Write command header\n    oos.writeByte(Command.NUMBER);\n\n    // Write name\n    oos.writeUTF(\"test\");\n\n    // Write WRONG type (String instead of Number)\n    oos.writeObject(\"not a number\");\n    oos.flush();\n\n    // Try to deserialize - should fail during WireIO.read()\n    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n    ObjectInputStream ois = new ObjectInputStream(bais);\n\n    IOException thrown = assertThrows(IOException.class, () -> {\n      WireIO.read(ois);\n    });\n    assertTrue(thrown.getMessage().contains(\"Invalid data type\"));\n  }\n\n  @Test\n  void testErrorCommandValidThrowable() throws Exception {\n    Throwable cause = new RuntimeException(\"test error\");\n    ErrorCommand cmd = new ErrorCommand(cause);\n\n    ErrorCommand deserialized = roundTrip(cmd, ErrorCommand.class);\n\n    assertNotNull(deserialized.getCause());\n    assertEquals(\"test error\", deserialized.getCause().getMessage());\n  }\n\n  @Test\n  void testErrorCommandNullCause() throws Exception {\n    ErrorCommand cmd = new ErrorCommand(null);\n\n    ErrorCommand deserialized = roundTrip(cmd, ErrorCommand.class);\n\n    assertNull(deserialized.getCause());\n  }\n\n  @Test\n  void testErrorCommandRejectsInvalidType() throws Exception {\n    // Create a command and manually serialize with wrong type\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    ObjectOutputStream oos = new ObjectOutputStream(baos);\n\n    // Write command header\n    oos.writeByte(Command.ERROR);\n\n    // Write WRONG type (String instead of Throwable)\n    oos.writeObject(\"not a throwable\");\n    oos.flush();\n\n    // Try to deserialize\n    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n    ObjectInputStream ois = new ObjectInputStream(bais);\n\n    IOException thrown = assertThrows(IOException.class, () -> {\n      WireIO.read(ois);\n    });\n    assertTrue(thrown.getMessage().contains(\"Invalid data type\"));\n  }\n\n  @Test\n  void testSetSettingsCommandValidTypes() throws Exception {\n    Map<String, Object> params = new HashMap<>();\n    params.put(\"string_param\", \"value\");\n    params.put(\"int_param\", 42);\n    params.put(\"bool_param\", true);\n    params.put(\"long_param\", 123L);\n    params.put(\"double_param\", 3.14);\n\n    SetSettingsCommand cmd = new SetSettingsCommand(params);\n    SetSettingsCommand deserialized = roundTrip(cmd, SetSettingsCommand.class);\n\n    assertEquals(5, deserialized.getParams().size());\n    assertEquals(\"value\", deserialized.getParams().get(\"string_param\"));\n    assertEquals(42, deserialized.getParams().get(\"int_param\"));\n    assertEquals(true, deserialized.getParams().get(\"bool_param\"));\n    assertEquals(123L, deserialized.getParams().get(\"long_param\"));\n    assertEquals(3.14, deserialized.getParams().get(\"double_param\"));\n  }\n\n  @Test\n  void testSetSettingsCommandRejectsInvalidType() throws Exception {\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    ObjectOutputStream oos = new ObjectOutputStream(baos);\n\n    // Write command header\n    oos.writeByte(Command.SET_PARAMS);\n\n    // Write params with invalid type (use a serializable but invalid type)\n    oos.writeInt(1); // size\n    oos.writeUTF(\"bad_param\");\n    oos.writeObject(new java.util.ArrayList<>()); // Invalid type - ArrayList is serializable but not a valid settings type\n    oos.flush();\n\n    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n    ObjectInputStream ois = new ObjectInputStream(bais);\n\n    IOException thrown = assertThrows(IOException.class, () -> {\n      WireIO.read(ois);\n    });\n    assertTrue(thrown.getMessage().contains(\"Invalid settings value type\"));\n  }\n\n  @Test\n  void testSetSettingsCommandRejectsNegativeSize() throws Exception {\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    ObjectOutputStream oos = new ObjectOutputStream(baos);\n\n    oos.writeByte(Command.SET_PARAMS);\n    oos.writeInt(-1); // Negative size!\n    oos.flush();\n\n    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n    ObjectInputStream ois = new ObjectInputStream(bais);\n\n    IOException thrown = assertThrows(IOException.class, () -> {\n      WireIO.read(ois);\n    });\n    assertTrue(thrown.getMessage().contains(\"Invalid params size\"));\n  }\n\n  @Test\n  void testSetSettingsCommandRejectsExcessiveSize() throws Exception {\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    ObjectOutputStream oos = new ObjectOutputStream(baos);\n\n    oos.writeByte(Command.SET_PARAMS);\n    oos.writeInt(100000); // Excessive size!\n    oos.flush();\n\n    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n    ObjectInputStream ois = new ObjectInputStream(bais);\n\n    IOException thrown = assertThrows(IOException.class, () -> {\n      WireIO.read(ois);\n    });\n    assertTrue(thrown.getMessage().contains(\"Invalid params size\"));\n  }\n\n  // Helper method to serialize and deserialize a command\n  private <T extends Command> T roundTrip(T cmd, Class<T> clazz) throws Exception {\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    ObjectOutputStream oos = new ObjectOutputStream(baos);\n    WireIO.write(oos, cmd);\n    oos.flush();\n\n    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n    ObjectInputStream ois = new ObjectInputStream(bais);\n    Command result = WireIO.read(ois);\n\n    assertInstanceOf(clazz, result);\n    return clazz.cast(result);\n  }\n}\n\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/WireProtocolSessionTest.java",
    "content": "package org.openjdk.btrace.core.comm;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.PipedInputStream;\nimport java.io.PipedOutputStream;\nimport java.io.PushbackInputStream;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport org.junit.jupiter.api.Test;\n\nclass WireProtocolSessionTest {\n  private interface SessionHandler {\n    void handle(WireProtocol protocol) throws Exception;\n  }\n\n  @Test\n  void testDisconnectThenListProbesAcrossConnections() throws Exception {\n    String probeId = \"probe-12345\";\n    String probeEntry = probeId + \" [OnMethodTest]\";\n\n    runV2Session(\n        protocol -> {\n          Command cmd = protocol.read();\n          assertTrue(cmd instanceof DisconnectCommand);\n          protocol.write(new DisconnectCommand(probeId));\n          protocol.flush();\n        },\n        protocol -> {\n          protocol.write(new DisconnectCommand());\n          protocol.flush();\n          Command cmd = protocol.read();\n          assertTrue(cmd instanceof DisconnectCommand);\n          assertEquals(probeId, ((DisconnectCommand) cmd).getProbeId());\n        });\n\n    runV2Session(\n        protocol -> {\n          Command cmd = protocol.read();\n          assertTrue(cmd instanceof ListProbesCommand);\n          ListProbesCommand response = (ListProbesCommand) cmd;\n          response.setProbes(Collections.singletonList(probeEntry));\n          protocol.write(response);\n          protocol.flush();\n        },\n        protocol -> {\n          protocol.write(new ListProbesCommand());\n          protocol.flush();\n          Command cmd = protocol.read();\n          assertTrue(cmd instanceof ListProbesCommand);\n          List<String> probes = ((ListProbesCommand) cmd).getProbes();\n          assertEquals(1, probes.size());\n          assertEquals(probeEntry, probes.get(0));\n        });\n  }\n\n  private static void runV2Session(SessionHandler serverHandler, SessionHandler clientHandler)\n      throws Exception {\n    Duplex duplex = new Duplex();\n    ExecutorService executor = Executors.newSingleThreadExecutor();\n    Future<?> serverFuture =\n        executor.submit(\n            () -> {\n              try (WireProtocol protocol =\n                  createServerProtocol(duplex.serverIn, duplex.serverOut)) {\n                serverHandler.handle(protocol);\n              } catch (Exception e) {\n                throw new RuntimeException(e);\n              }\n            });\n\n    try (WireProtocol protocol = createClientProtocol(duplex.clientIn, duplex.clientOut)) {\n      clientHandler.handle(protocol);\n    }\n\n    try {\n      serverFuture.get(5, TimeUnit.SECONDS);\n    } catch (ExecutionException e) {\n      throw unwrap(e);\n    } catch (TimeoutException e) {\n      throw new AssertionError(\"Server session did not complete in time\", e);\n    } finally {\n      executor.shutdownNow();\n    }\n  }\n\n  private static WireProtocol createServerProtocol(InputStream in, OutputStream out)\n      throws Exception {\n    ProtocolNegotiator negotiator = new ProtocolNegotiator(ProtocolVersion.V2);\n    PushbackInputStream input = ProtocolNegotiator.createNegotiationStream(in);\n    ProtocolVersion negotiated = negotiator.negotiateAgent(input, out);\n    assertEquals(ProtocolVersion.V2, negotiated);\n    WireProtocol protocol = new BinaryWireProtocol(input, out);\n    assertEquals(ProtocolVersion.V2, protocol.getVersion());\n    return protocol;\n  }\n\n  private static WireProtocol createClientProtocol(InputStream in, OutputStream out)\n      throws Exception {\n    ProtocolNegotiator negotiator = new ProtocolNegotiator(ProtocolVersion.V2);\n    ProtocolVersion negotiated = negotiator.negotiateClient(in, out, ProtocolVersion.V2);\n    assertEquals(ProtocolVersion.V2, negotiated);\n    WireProtocol protocol = new BinaryWireProtocol(in, out);\n    assertEquals(ProtocolVersion.V2, protocol.getVersion());\n    return protocol;\n  }\n\n  private static Exception unwrap(ExecutionException e) {\n    Throwable cause = e.getCause();\n    if (cause instanceof Exception) {\n      return (Exception) cause;\n    }\n    return new RuntimeException(cause);\n  }\n\n  private static final class Duplex {\n    final InputStream clientIn;\n    final OutputStream clientOut;\n    final InputStream serverIn;\n    final OutputStream serverOut;\n\n    Duplex() throws Exception {\n      PipedInputStream clientInput = new PipedInputStream(32 * 1024);\n      PipedInputStream serverInput = new PipedInputStream(32 * 1024);\n      this.clientOut = new PipedOutputStream(serverInput);\n      this.serverOut = new PipedOutputStream(clientInput);\n      this.clientIn = clientInput;\n      this.serverIn = serverInput;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/WireProtocolTest.java",
    "content": "package org.openjdk.btrace.core.comm;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PipedInputStream;\nimport java.io.PipedOutputStream;\nimport org.junit.jupiter.api.Test;\n\n/** Tests for WireProtocol interface and implementations. */\npublic class WireProtocolTest {\n\n  @Test\n  public void testJavaSerializationProtocolBasic() throws Exception {\n    // Use piped streams for proper ObjectStream initialization\n    PipedOutputStream pos = new PipedOutputStream();\n    PipedInputStream pis = new PipedInputStream(pos);\n\n    // Create protocols\n    WireProtocol writer = WireProtocol.create(ProtocolVersion.V1, pis, pos);\n\n    // Write command in separate thread to avoid deadlock\n    Thread writerThread = new Thread(() -> {\n      try {\n        Command cmd = new MessageCommand(\"test message\");\n        writer.write(cmd);\n        writer.flush();\n      } catch (IOException e) {\n        throw new RuntimeException(e);\n      }\n    });\n    writerThread.start();\n\n    // Read command\n    Command readCmd = writer.read();\n\n    assertEquals(Command.MESSAGE, readCmd.getType());\n    assertTrue(readCmd instanceof MessageCommand);\n    assertEquals(\"test message\", ((MessageCommand) readCmd).getMessage());\n    assertEquals(ProtocolVersion.V1, writer.getVersion());\n\n    writerThread.join();\n  }\n\n  @Test\n  public void testBinaryWireProtocolBasic() throws Exception {\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n    // Write with binary protocol\n    WireProtocol writer = new BinaryWireProtocol(new ByteArrayInputStream(new byte[0]), baos);\n    Command cmd = new MessageCommand(\"test message\");\n    writer.write(cmd);\n    writer.flush();\n\n    // Read with binary protocol\n    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n    WireProtocol reader = new BinaryWireProtocol(bais, new ByteArrayOutputStream());\n    Command readCmd = reader.read();\n\n    assertEquals(Command.MESSAGE, readCmd.getType());\n    assertTrue(readCmd instanceof MessageCommand);\n    assertEquals(\"test message\", ((MessageCommand) readCmd).getMessage());\n    assertEquals(ProtocolVersion.V2, reader.getVersion());\n  }\n\n  @Test\n  public void testWireProtocolCreateV1() throws Exception {\n    PipedOutputStream pos = new PipedOutputStream();\n    PipedInputStream pis = new PipedInputStream(pos);\n\n    WireProtocol protocol = WireProtocol.create(ProtocolVersion.V1, pis, pos);\n\n    assertTrue(protocol instanceof JavaSerializationProtocol);\n    assertEquals(ProtocolVersion.V1, protocol.getVersion());\n    protocol.close();\n  }\n\n  @Test\n  public void testWireProtocolCreateV2() throws Exception {\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    WireProtocol protocol =\n        WireProtocol.create(ProtocolVersion.V2, new ByteArrayInputStream(new byte[0]), baos);\n\n    assertTrue(protocol instanceof BinaryWireProtocol);\n    assertEquals(ProtocolVersion.V2, protocol.getVersion());\n  }\n\n  @Test\n  public void testWireProtocolWithNegotiationV2() throws Exception {\n    // Create stream with V2 magic bytes\n    ByteArrayOutputStream setupStream = new ByteArrayOutputStream();\n    setupStream.write(new byte[] {0x42, 0x54, 0x52, 0x32}); // \"BTR2\"\n\n    // Add some dummy data for the protocol to work with\n    ByteArrayInputStream inputStream = new ByteArrayInputStream(setupStream.toByteArray());\n    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\n    WireProtocol protocol = WireProtocol.createWithNegotiation(inputStream, outputStream);\n\n    assertEquals(ProtocolVersion.V2, protocol.getVersion());\n    assertTrue(protocol instanceof BinaryWireProtocol);\n  }\n\n  @Test\n  public void testWireProtocolWithNegotiationV1() throws Exception {\n    // Create stream with Java serialization header\n    ByteArrayOutputStream setupStream = new ByteArrayOutputStream();\n    setupStream.write(new byte[] {(byte) 0xAC, (byte) 0xED, 0x00, 0x05});\n\n    ByteArrayInputStream inputStream = new ByteArrayInputStream(setupStream.toByteArray());\n    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\n    WireProtocol protocol = WireProtocol.createWithNegotiation(inputStream, outputStream);\n\n    assertEquals(ProtocolVersion.V1, protocol.getVersion());\n    assertTrue(protocol instanceof JavaSerializationProtocol);\n  }\n\n  @Test\n  public void testWireProtocolWithConfigForceV1() throws Exception {\n    ProtocolConfig config =\n        ProtocolConfig.builder()\n            .version(ProtocolVersion.V1)\n            .autoNegotiate(false)\n            .forceVersion(true)\n            .build();\n\n    PipedOutputStream pos = new PipedOutputStream();\n    PipedInputStream pis = new PipedInputStream(pos);\n\n    WireProtocol protocol = WireProtocol.createWithConfig(config, pis, pos);\n\n    assertEquals(ProtocolVersion.V1, protocol.getVersion());\n    assertTrue(protocol instanceof JavaSerializationProtocol);\n    protocol.close();\n  }\n\n  @Test\n  public void testWireProtocolWithConfigAutoNegotiate() throws Exception {\n    ProtocolConfig config =\n        ProtocolConfig.builder()\n            .version(ProtocolVersion.V2) // Preferred version\n            .autoNegotiate(true)\n            .build();\n\n    // Stream with V2 magic bytes\n    ByteArrayOutputStream setupStream = new ByteArrayOutputStream();\n    setupStream.write(new byte[] {0x42, 0x54, 0x52, 0x32});\n\n    ByteArrayInputStream inputStream = new ByteArrayInputStream(setupStream.toByteArray());\n    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\n    WireProtocol protocol = WireProtocol.createWithConfig(config, inputStream, outputStream);\n\n    assertEquals(ProtocolVersion.V2, protocol.getVersion());\n  }\n\n  @Test\n  public void testMultipleCommandsV1() throws Exception {\n    PipedOutputStream pos = new PipedOutputStream();\n    PipedInputStream pis = new PipedInputStream(pos);\n\n    // Single protocol for both read and write\n    WireProtocol protocol = new JavaSerializationProtocol(pis, pos);\n\n    // Write multiple commands in separate thread\n    Thread writerThread = new Thread(() -> {\n      try {\n        protocol.write(new MessageCommand(\"msg1\"));\n        protocol.write(new MessageCommand(\"msg2\"));\n        protocol.write(new ExitCommand(0));\n        protocol.flush();\n      } catch (IOException e) {\n        throw new RuntimeException(e);\n      }\n    });\n    writerThread.start();\n\n    // Read multiple commands\n    Command cmd1 = protocol.read();\n    assertEquals(\"msg1\", ((MessageCommand) cmd1).getMessage());\n\n    Command cmd2 = protocol.read();\n    assertEquals(\"msg2\", ((MessageCommand) cmd2).getMessage());\n\n    Command cmd3 = protocol.read();\n    assertEquals(Command.EXIT, cmd3.getType());\n\n    writerThread.join();\n    protocol.close();\n  }\n\n  @Test\n  public void testMultipleCommandsV2() throws Exception {\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n    WireProtocol writer = new BinaryWireProtocol(new ByteArrayInputStream(new byte[0]), baos);\n\n    // Write multiple commands\n    writer.write(new MessageCommand(\"msg1\"));\n    writer.write(new MessageCommand(\"msg2\"));\n    writer.write(new ExitCommand(0));\n    writer.flush();\n\n    // Read multiple commands\n    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n    WireProtocol reader = new BinaryWireProtocol(bais, new ByteArrayOutputStream());\n\n    Command cmd1 = reader.read();\n    assertEquals(\"msg1\", ((MessageCommand) cmd1).getMessage());\n\n    Command cmd2 = reader.read();\n    assertEquals(\"msg2\", ((MessageCommand) cmd2).getMessage());\n\n    Command cmd3 = reader.read();\n    assertEquals(Command.EXIT, cmd3.getType());\n  }\n\n  @Test\n  public void testCloseV1() throws Exception {\n    PipedOutputStream pos = new PipedOutputStream();\n    PipedInputStream pis = new PipedInputStream(pos);\n    WireProtocol protocol = new JavaSerializationProtocol(pis, pos);\n\n    protocol.close();\n\n    assertThrows(IOException.class, () -> protocol.write(new MessageCommand(\"test\")));\n    assertThrows(IOException.class, () -> protocol.read());\n  }\n\n  @Test\n  public void testCloseV2() throws Exception {\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    WireProtocol protocol = new BinaryWireProtocol(new ByteArrayInputStream(new byte[0]), baos);\n\n    protocol.close();\n\n    assertThrows(IOException.class, () -> protocol.write(new MessageCommand(\"test\")));\n    assertThrows(IOException.class, () -> protocol.read());\n  }\n\n  @Test\n  public void testJavaSerializationProtocolReset() throws Exception {\n    PipedOutputStream pos = new PipedOutputStream();\n    PipedInputStream pis = new PipedInputStream(pos);\n    JavaSerializationProtocol protocol = new JavaSerializationProtocol(pis, pos);\n\n    // Reset should not throw\n    protocol.reset();\n\n    // Should still be able to write after reset (in separate thread to avoid deadlock)\n    Thread writerThread = new Thread(() -> {\n      try {\n        protocol.write(new MessageCommand(\"test\"));\n        protocol.flush();\n      } catch (IOException e) {\n        throw new RuntimeException(e);\n      }\n    });\n    writerThread.start();\n    writerThread.join();\n\n    protocol.close();\n  }\n\n  @Test\n  public void testJavaSerializationProtocolAccessors() throws Exception {\n    PipedOutputStream pos = new PipedOutputStream();\n    PipedInputStream pis = new PipedInputStream(pos);\n    JavaSerializationProtocol protocol = new JavaSerializationProtocol(pis, pos);\n\n    assertNotNull(protocol.getObjectInputStream());\n    assertNotNull(protocol.getObjectOutputStream());\n    protocol.close();\n  }\n\n  @Test\n  public void testBinaryWireProtocolAccessors() throws Exception {\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]);\n    BinaryWireProtocol protocol = new BinaryWireProtocol(bais, baos);\n\n    assertSame(bais, protocol.getInputStream());\n    assertSame(baos, protocol.getOutputStream());\n  }\n\n  @Test\n  public void testV1V2Interoperability() throws Exception {\n    // Test V2 - simpler with byte arrays\n    ByteArrayOutputStream v2Stream = new ByteArrayOutputStream();\n    WireProtocol v2Writer = new BinaryWireProtocol(new ByteArrayInputStream(new byte[0]), v2Stream);\n    v2Writer.write(new MessageCommand(\"v2 message\"));\n    v2Writer.flush();\n\n    // Read with V2\n    WireProtocol v2Reader =\n        new BinaryWireProtocol(\n            new ByteArrayInputStream(v2Stream.toByteArray()), new ByteArrayOutputStream());\n    Command v2Cmd = v2Reader.read();\n    assertEquals(\"v2 message\", ((MessageCommand) v2Cmd).getMessage());\n    v2Reader.close();\n\n    // Test V1 with piped streams\n    PipedOutputStream pos = new PipedOutputStream();\n    PipedInputStream pis = new PipedInputStream(pos);\n    WireProtocol v1Protocol = new JavaSerializationProtocol(pis, pos);\n\n    // Write in separate thread\n    Thread writerThread = new Thread(() -> {\n      try {\n        v1Protocol.write(new MessageCommand(\"v1 message\"));\n        v1Protocol.flush();\n      } catch (IOException e) {\n        throw new RuntimeException(e);\n      }\n    });\n    writerThread.start();\n\n    // Read\n    Command v1Cmd = v1Protocol.read();\n    assertEquals(\"v1 message\", ((MessageCommand) v1Cmd).getMessage());\n\n    writerThread.join();\n    v1Protocol.close();\n  }\n}\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/v2/BinaryProtocolEdgeCasesTest.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\n/**\n * Edge case tests for the binary protocol.\n * Tests null values, empty collections, large payloads, boundary conditions, and malformed data.\n */\npublic class BinaryProtocolEdgeCasesTest {\n\n    // ===== NULL AND EMPTY VALUE TESTS =====\n\n    @Test\n    public void testNullString() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryProtocol.writeString(baos, null);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        String result = BinaryProtocol.readString(bais);\n        assertNull(result);\n    }\n\n    @Test\n    public void testEmptyString() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryProtocol.writeString(baos, \"\");\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        String result = BinaryProtocol.readString(bais);\n        assertNotNull(result);\n        assertEquals(\"\", result);\n    }\n\n    @Test\n    public void testNullByteArray() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryProtocol.writeByteArray(baos, null);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        byte[] result = BinaryProtocol.readByteArray(bais);\n        assertNull(result);\n    }\n\n    @Test\n    public void testEmptyByteArray() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryProtocol.writeByteArray(baos, new byte[0]);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        byte[] result = BinaryProtocol.readByteArray(bais);\n        assertNotNull(result);\n        assertEquals(0, result.length);\n    }\n\n    @Test\n    public void testMessageCommandNullMessage() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        BinaryMessageCommand original = new BinaryMessageCommand(null, false);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryMessageCommand);\n        BinaryMessageCommand msgCommand = (BinaryMessageCommand) readCommand;\n        // Empty message should be preserved as empty string (not null)\n        assertEquals(\"\", msgCommand.getMessage());\n    }\n\n    @Test\n    public void testErrorCommandNullMessage() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        BinaryErrorCommand original = new BinaryErrorCommand(\"java.lang.RuntimeException\", null, null);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryErrorCommand);\n        BinaryErrorCommand errorCommand = (BinaryErrorCommand) readCommand;\n        assertEquals(\"java.lang.RuntimeException\", errorCommand.getExceptionClass());\n        assertNull(errorCommand.getMessage());\n        assertNull(errorCommand.getStackTrace());\n    }\n\n    @Test\n    public void testEventCommandNullEvent() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        BinaryEventCommand original = new BinaryEventCommand(null);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryEventCommand);\n        BinaryEventCommand eventCommand = (BinaryEventCommand) readCommand;\n        assertNull(eventCommand.getEvent());\n    }\n\n    @Test\n    public void testStringMapWithNullValues() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        Map<String, String> data = new HashMap<>();\n        data.put(\"key1\", \"value1\");\n        data.put(\"key2\", null);\n        data.put(\"key3\", \"\");\n\n        BinaryStringMapDataCommand original = new BinaryStringMapDataCommand(\"TestMap\", data);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryStringMapDataCommand);\n        BinaryStringMapDataCommand mapCommand = (BinaryStringMapDataCommand) readCommand;\n        Map<String, String> readData = mapCommand.getData();\n        assertEquals(\"value1\", readData.get(\"key1\"));\n        assertNull(readData.get(\"key2\"));\n        assertEquals(\"\", readData.get(\"key3\"));\n    }\n\n    @Test\n    public void testEmptyNumberMap() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        Map<String, Number> data = new HashMap<>();\n        BinaryNumberMapDataCommand original = new BinaryNumberMapDataCommand(\"EmptyMap\", data);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryNumberMapDataCommand);\n        BinaryNumberMapDataCommand mapCommand = (BinaryNumberMapDataCommand) readCommand;\n        assertTrue(mapCommand.getData().isEmpty());\n    }\n\n    // ===== BOUNDARY CONDITION TESTS =====\n\n    @Test\n    public void testVeryLargeMessage() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create a 10MB message\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < 10 * 1024 * 1024; i++) {\n            sb.append('A');\n        }\n        String largeMessage = sb.toString();\n\n        BinaryMessageCommand original = new BinaryMessageCommand(largeMessage, false);\n        BinaryWireIO.write(baos, original);\n\n        // Verify it was written\n        assertTrue(baos.size() > 0);\n\n        // Verify it can be read back\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryMessageCommand);\n        BinaryMessageCommand msgCommand = (BinaryMessageCommand) readCommand;\n        assertEquals(largeMessage.length(), msgCommand.getMessage().length());\n        assertEquals(largeMessage, msgCommand.getMessage());\n    }\n\n    @Test\n    public void testLargeBytecodeArray() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create a 1MB bytecode array\n        byte[] largeCode = new byte[1024 * 1024];\n        for (int i = 0; i < largeCode.length; i++) {\n            largeCode[i] = (byte) (i % 256);\n        }\n\n        Map<String, String> args = new HashMap<>();\n        args.put(\"test\", \"value\");\n\n        BinaryInstrumentCommand original = new BinaryInstrumentCommand(largeCode, args);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryInstrumentCommand);\n        BinaryInstrumentCommand instrCommand = (BinaryInstrumentCommand) readCommand;\n        assertArrayEquals(largeCode, instrCommand.getCode());\n    }\n\n    @Test\n    public void testMapWith1000Entries() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        Map<String, Number> data = new HashMap<>();\n        for (int i = 0; i < 1000; i++) {\n            data.put(\"key\" + i, i);\n        }\n\n        BinaryNumberMapDataCommand original = new BinaryNumberMapDataCommand(\"LargeMap\", data);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryNumberMapDataCommand);\n        BinaryNumberMapDataCommand mapCommand = (BinaryNumberMapDataCommand) readCommand;\n        assertEquals(1000, mapCommand.getData().size());\n        for (int i = 0; i < 1000; i++) {\n            assertEquals(i, mapCommand.getData().get(\"key\" + i).intValue());\n        }\n    }\n\n    @Test\n    public void testGridDataWithManyRows() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        List<String> columnNames = new ArrayList<>();\n        columnNames.add(\"Col1\");\n        columnNames.add(\"Col2\");\n\n        List<Object[]> data = new ArrayList<>();\n        for (int i = 0; i < 500; i++) {\n            data.add(new Object[]{\"Row\" + i, i});\n        }\n\n        BinaryGridDataCommand original = new BinaryGridDataCommand(\"LargeGrid\", columnNames, data);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryGridDataCommand);\n        BinaryGridDataCommand gridCommand = (BinaryGridDataCommand) readCommand;\n        assertEquals(500, gridCommand.getData().size());\n    }\n\n    // ===== UNICODE AND SPECIAL CHARACTER TESTS =====\n\n    @Test\n    public void testUnicodeStrings() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Test various Unicode characters\n        String unicode = \"Hello 世界 🌍 مرحبا Привет\";\n        BinaryMessageCommand original = new BinaryMessageCommand(unicode, false);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryMessageCommand);\n        BinaryMessageCommand msgCommand = (BinaryMessageCommand) readCommand;\n        assertEquals(unicode, msgCommand.getMessage());\n    }\n\n    @Test\n    public void testEmojiInMessage() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        String emoji = \"🚀 BTrace launched! 🎉🎊🎈\";\n        BinaryMessageCommand original = new BinaryMessageCommand(emoji, false);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryMessageCommand);\n        BinaryMessageCommand msgCommand = (BinaryMessageCommand) readCommand;\n        assertEquals(emoji, msgCommand.getMessage());\n    }\n\n    @Test\n    public void testControlCharactersInString() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        String controlChars = \"Line1\\nLine2\\tTabbed\\rCarriageReturn\\0Null\";\n        BinaryProtocol.writeString(baos, controlChars);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        String result = BinaryProtocol.readString(bais);\n        assertEquals(controlChars, result);\n    }\n\n    // ===== MALFORMED DATA TESTS =====\n\n    @Test\n    public void testInvalidProtocolVersion() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Write invalid protocol version\n        BinaryProtocol.writeByte(baos, (byte) 99);  // Invalid version\n        BinaryProtocol.writeByte(baos, BinaryCommand.MESSAGE);  // Valid command type\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n\n        // Should throw IOException due to version mismatch\n        assertThrows(IOException.class, () -> {\n            BinaryWireIO.read(bais);\n        });\n    }\n\n    @Test\n    public void testInvalidCommandType() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Write valid protocol version but invalid command type\n        BinaryProtocol.writeByte(baos, BinaryProtocol.VERSION);\n        BinaryProtocol.writeByte(baos, (byte) 99);  // Invalid command type\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n\n        // Should throw MalformedCommandException due to unknown command type\n        assertThrows(MalformedCommandException.class, () -> {\n            BinaryWireIO.read(bais);\n        });\n    }\n\n    @Test\n    public void testTruncatedStream() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Write only protocol version and command type, but not the data\n        BinaryProtocol.writeByte(baos, BinaryProtocol.VERSION);\n        BinaryProtocol.writeByte(baos, BinaryCommand.MESSAGE);\n        // Missing message data...\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n\n        // Should throw IOException due to unexpected end of stream\n        assertThrows(IOException.class, () -> {\n            BinaryWireIO.read(bais);\n        });\n    }\n\n    // ===== COMPRESSION EDGE CASES =====\n\n    @Test\n    public void testCompressionThreshold() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create message exactly at threshold (1024 bytes)\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < 1024; i++) {\n            sb.append('X');\n        }\n        String thresholdMessage = sb.toString();\n\n        BinaryMessageCommand original = new BinaryMessageCommand(thresholdMessage, false);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryMessageCommand);\n        BinaryMessageCommand msgCommand = (BinaryMessageCommand) readCommand;\n        assertEquals(thresholdMessage, msgCommand.getMessage());\n    }\n\n    @Test\n    public void testCompressionJustAboveThreshold() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create message just above threshold (1025 bytes)\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < 1025; i++) {\n            sb.append('Y');\n        }\n        String aboveThresholdMessage = sb.toString();\n\n        BinaryMessageCommand original = new BinaryMessageCommand(aboveThresholdMessage, false);\n        BinaryWireIO.write(baos, original);\n\n        // Message should be compressed, verify it's smaller than original\n        int wireSize = baos.size();\n        // Wire size should be less than original due to compression\n        // (accounting for protocol overhead)\n        assertTrue(wireSize < aboveThresholdMessage.length());\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryMessageCommand);\n        BinaryMessageCommand msgCommand = (BinaryMessageCommand) readCommand;\n        assertEquals(aboveThresholdMessage, msgCommand.getMessage());\n    }\n\n    @Test\n    public void testHighlyCompressibleMessage() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create highly compressible message (many repeated characters)\n        String compressible = \"AAAAAAAAAA\".repeat(1000);  // 10,000 'A's\n\n        BinaryMessageCommand original = new BinaryMessageCommand(compressible, false);\n        BinaryWireIO.write(baos, original);\n\n        // Compressed size should be much smaller than original\n        int wireSize = baos.size();\n        assertTrue(wireSize < compressible.length() / 5);  // Should compress to less than 20%\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryMessageCommand);\n        BinaryMessageCommand msgCommand = (BinaryMessageCommand) readCommand;\n        assertEquals(compressible, msgCommand.getMessage());\n    }\n\n    // ===== NUMERIC BOUNDARY TESTS =====\n\n    @ParameterizedTest\n    @ValueSource(ints = {Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE})\n    public void testIntegerBoundaries(int value) throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryProtocol.writeInt(baos, value);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        int result = BinaryProtocol.readInt(bais);\n        assertEquals(value, result);\n    }\n\n    @ParameterizedTest\n    @ValueSource(longs = {Long.MIN_VALUE, -1L, 0L, 1L, Long.MAX_VALUE})\n    public void testLongBoundaries(long value) throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryProtocol.writeLong(baos, value);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        long result = BinaryProtocol.readLong(bais);\n        assertEquals(value, result);\n    }\n\n    @Test\n    public void testSpecialFloatValues() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Test special float values\n        BinaryProtocol.writeFloat(baos, Float.NaN);\n        BinaryProtocol.writeFloat(baos, Float.POSITIVE_INFINITY);\n        BinaryProtocol.writeFloat(baos, Float.NEGATIVE_INFINITY);\n        BinaryProtocol.writeFloat(baos, Float.MIN_VALUE);\n        BinaryProtocol.writeFloat(baos, Float.MAX_VALUE);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        assertTrue(Float.isNaN(BinaryProtocol.readFloat(bais)));\n        assertEquals(Float.POSITIVE_INFINITY, BinaryProtocol.readFloat(bais));\n        assertEquals(Float.NEGATIVE_INFINITY, BinaryProtocol.readFloat(bais));\n        assertEquals(Float.MIN_VALUE, BinaryProtocol.readFloat(bais));\n        assertEquals(Float.MAX_VALUE, BinaryProtocol.readFloat(bais));\n    }\n\n    @Test\n    public void testSpecialDoubleValues() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Test special double values\n        BinaryProtocol.writeDouble(baos, Double.NaN);\n        BinaryProtocol.writeDouble(baos, Double.POSITIVE_INFINITY);\n        BinaryProtocol.writeDouble(baos, Double.NEGATIVE_INFINITY);\n        BinaryProtocol.writeDouble(baos, Double.MIN_VALUE);\n        BinaryProtocol.writeDouble(baos, Double.MAX_VALUE);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        assertTrue(Double.isNaN(BinaryProtocol.readDouble(bais)));\n        assertEquals(Double.POSITIVE_INFINITY, BinaryProtocol.readDouble(bais));\n        assertEquals(Double.NEGATIVE_INFINITY, BinaryProtocol.readDouble(bais));\n        assertEquals(Double.MIN_VALUE, BinaryProtocol.readDouble(bais));\n        assertEquals(Double.MAX_VALUE, BinaryProtocol.readDouble(bais));\n    }\n\n    // ===== SETTINGS COMMAND EDGE CASES =====\n\n    @Test\n    public void testSetSettingsCommandWithMixedTypes() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        Map<String, Object> settings = new HashMap<>();\n        settings.put(\"stringValue\", \"test\");\n        settings.put(\"intValue\", 42);\n        settings.put(\"longValue\", 9876543210L);\n        settings.put(\"boolValue\", true);\n        settings.put(\"floatValue\", 3.14f);\n        settings.put(\"doubleValue\", 2.71828);\n        settings.put(\"nullValue\", null);\n\n        BinarySetSettingsCommand original = new BinarySetSettingsCommand(settings);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinarySetSettingsCommand);\n        BinarySetSettingsCommand settingsCommand = (BinarySetSettingsCommand) readCommand;\n        Map<String, Object> readSettings = settingsCommand.getParams();\n\n        assertEquals(\"test\", readSettings.get(\"stringValue\"));\n        assertEquals(42, readSettings.get(\"intValue\"));\n        assertEquals(9876543210L, readSettings.get(\"longValue\"));\n        assertEquals(true, readSettings.get(\"boolValue\"));\n        assertEquals(3.14f, ((Number) readSettings.get(\"floatValue\")).floatValue(), 0.001);\n        assertEquals(2.71828, ((Number) readSettings.get(\"doubleValue\")).doubleValue(), 0.00001);\n        assertNull(readSettings.get(\"nullValue\"));\n    }\n}\n"
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/v2/BinaryProtocolPerformanceTest.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.InstrumentCommand;\nimport org.openjdk.btrace.core.comm.MessageCommand;\nimport org.openjdk.btrace.core.comm.WireIO;\n\n/**\n * Performance tests comparing the binary protocol to Java serialization.\n * This is not included in the regular test suite to avoid slowing down normal builds.\n */\npublic class BinaryProtocolPerformanceTest {\n\n    private static final int ITERATIONS = 10000;\n    private static final byte[] SAMPLE_CODE = new byte[1024]; // 1KB of code\n    private static final String LARGE_MESSAGE = generateLargeMessage(10 * 1024); // 10KB message\n\n    static {\n        // Initialize sample code with random data\n        for (int i = 0; i < SAMPLE_CODE.length; i++) {\n            SAMPLE_CODE[i] = (byte) (Math.random() * 256);\n        }\n    }\n\n    private static String generateLargeMessage(int size) {\n        StringBuilder sb = new StringBuilder(size);\n        for (int i = 0; i < size; i++) {\n            sb.append((char) ('a' + (i % 26)));\n        }\n        return sb.toString();\n    }\n\n    /**\n     * This test compares the performance of binary protocol vs Java serialization\n     * for the InstrumentCommand, which contains bytecode and arguments.\n     */\n    @Test\n    public void testInstrumentCommandPerformance() throws IOException, ClassNotFoundException {\n        // Create test data\n        Map<String, String> args = new HashMap<>();\n        args.put(\"className\", \"com.example.TestClass\");\n        args.put(\"methodName\", \"testMethod\");\n        args.put(\"probeId\", \"12345\");\n        \n        // Binary protocol\n        long binaryStartTime = System.nanoTime();\n        long binaryTotalSize = 0;\n        \n        for (int i = 0; i < ITERATIONS; i++) {\n            // Serialize\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            BinaryCommand cmd = new BinaryInstrumentCommand(SAMPLE_CODE, args);\n            BinaryWireIO.write(baos, cmd);\n            byte[] serialized = baos.toByteArray();\n            binaryTotalSize += serialized.length;\n            \n            // Deserialize\n            ByteArrayInputStream bais = new ByteArrayInputStream(serialized);\n            BinaryCommand deserialized = BinaryWireIO.read(bais);\n        }\n        \n        long binaryEndTime = System.nanoTime();\n        long binaryDuration = binaryEndTime - binaryStartTime;\n        \n        // Java serialization\n        long javaStartTime = System.nanoTime();\n        long javaTotalSize = 0;\n        \n        for (int i = 0; i < ITERATIONS; i++) {\n            // Serialize\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            ObjectOutputStream oos = new ObjectOutputStream(baos);\n            Command cmd = new InstrumentCommand(SAMPLE_CODE, args);\n            WireIO.write(oos, cmd);\n            oos.close();\n            byte[] serialized = baos.toByteArray();\n            javaTotalSize += serialized.length;\n\n            // Deserialize\n            ByteArrayInputStream bais = new ByteArrayInputStream(serialized);\n            ObjectInputStream ois = new ObjectInputStream(bais);\n            Command deserialized = WireIO.read(ois);\n            ois.close();\n        }\n        \n        long javaEndTime = System.nanoTime();\n        long javaDuration = javaEndTime - javaStartTime;\n        \n        // Print results\n        System.out.println(\"InstrumentCommand Performance Test Results:\");\n        System.out.println(\"  Binary Protocol:\");\n        System.out.println(\"    Time: \" + (binaryDuration / 1_000_000) + \" ms\");\n        System.out.println(\"    Avg Size: \" + (binaryTotalSize / ITERATIONS) + \" bytes\");\n        System.out.println(\"  Java Serialization:\");\n        System.out.println(\"    Time: \" + (javaDuration / 1_000_000) + \" ms\");\n        System.out.println(\"    Avg Size: \" + (javaTotalSize / ITERATIONS) + \" bytes\");\n        System.out.println(\"  Improvement:\");\n        System.out.println(\"    Time: \" + (javaDuration / (double)binaryDuration) + \"x faster\");\n        System.out.println(\"    Size: \" + (javaTotalSize / (double)binaryTotalSize) + \"x smaller\");\n    }\n    \n    /**\n     * This test compares the performance of binary protocol vs Java serialization\n     * for the MessageCommand with compression.\n     */\n    @Test\n    public void testMessageCommandPerformance() throws IOException, ClassNotFoundException {\n        // Binary protocol\n        long binaryStartTime = System.nanoTime();\n        long binaryTotalSize = 0;\n        \n        for (int i = 0; i < ITERATIONS; i++) {\n            // Serialize\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            BinaryCommand cmd = new BinaryMessageCommand(LARGE_MESSAGE, true);\n            BinaryWireIO.write(baos, cmd);\n            byte[] serialized = baos.toByteArray();\n            binaryTotalSize += serialized.length;\n            \n            // Deserialize\n            ByteArrayInputStream bais = new ByteArrayInputStream(serialized);\n            BinaryCommand deserialized = BinaryWireIO.read(bais);\n        }\n        \n        long binaryEndTime = System.nanoTime();\n        long binaryDuration = binaryEndTime - binaryStartTime;\n        \n        // Java serialization\n        long javaStartTime = System.nanoTime();\n        long javaTotalSize = 0;\n        \n        for (int i = 0; i < ITERATIONS; i++) {\n            // Serialize\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            ObjectOutputStream oos = new ObjectOutputStream(baos);\n            Command cmd = new MessageCommand(LARGE_MESSAGE);\n            WireIO.write(oos, cmd);\n            oos.close();\n            byte[] serialized = baos.toByteArray();\n            javaTotalSize += serialized.length;\n\n            // Deserialize\n            ByteArrayInputStream bais = new ByteArrayInputStream(serialized);\n            ObjectInputStream ois = new ObjectInputStream(bais);\n            Command deserialized = WireIO.read(ois);\n            ois.close();\n        }\n        \n        long javaEndTime = System.nanoTime();\n        long javaDuration = javaEndTime - javaStartTime;\n        \n        // Print results\n        System.out.println(\"MessageCommand Performance Test Results:\");\n        System.out.println(\"  Binary Protocol (with compression):\");\n        System.out.println(\"    Time: \" + (binaryDuration / 1_000_000) + \" ms\");\n        System.out.println(\"    Avg Size: \" + (binaryTotalSize / ITERATIONS) + \" bytes\");\n        System.out.println(\"  Java Serialization:\");\n        System.out.println(\"    Time: \" + (javaDuration / 1_000_000) + \" ms\");\n        System.out.println(\"    Avg Size: \" + (javaTotalSize / ITERATIONS) + \" bytes\");\n        System.out.println(\"  Improvement:\");\n        System.out.println(\"    Time: \" + (javaDuration / (double)binaryDuration) + \"x faster\");\n        System.out.println(\"    Size: \" + (javaTotalSize / (double)binaryTotalSize) + \"x smaller\");\n    }\n} "
  },
  {
    "path": "btrace-core/src/test/java/org/openjdk/btrace/core/comm/v2/BinaryProtocolTest.java",
    "content": "package org.openjdk.btrace.core.comm.v2;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.ArgsMap;\n\n/**\n * Tests for the binary protocol implementation.\n */\npublic class BinaryProtocolTest {\n\n    @Test\n    public void testBinaryProtocolBasicTypes() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        \n        // Write test data\n        BinaryProtocol.writeByte(baos, (byte) 123);\n        BinaryProtocol.writeInt(baos, 42);\n        BinaryProtocol.writeLong(baos, 9876543210L);\n        BinaryProtocol.writeFloat(baos, 3.14f);\n        BinaryProtocol.writeDouble(baos, 2.71828);\n        BinaryProtocol.writeBoolean(baos, true);\n        BinaryProtocol.writeString(baos, \"Hello, World!\");\n        byte[] testArray = {1, 2, 3, 4, 5};\n        BinaryProtocol.writeByteArray(baos, testArray);\n        \n        // Read test data\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        assertEquals((byte) 123, BinaryProtocol.readByte(bais));\n        assertEquals(42, BinaryProtocol.readInt(bais));\n        assertEquals(9876543210L, BinaryProtocol.readLong(bais));\n        assertEquals(3.14f, BinaryProtocol.readFloat(bais));\n        assertEquals(2.71828, BinaryProtocol.readDouble(bais));\n        assertTrue(BinaryProtocol.readBoolean(bais));\n        assertEquals(\"Hello, World!\", BinaryProtocol.readString(bais));\n        byte[] readArray = BinaryProtocol.readByteArray(bais);\n        assertArrayEquals(testArray, readArray);\n    }\n    \n    @Test\n    public void testBinaryExitCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        \n        // Create and write command\n        BinaryExitCommand original = new BinaryExitCommand(42);\n        BinaryWireIO.write(baos, original);\n        \n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n        \n        // Verify command\n        assertTrue(readCommand instanceof BinaryExitCommand);\n        BinaryExitCommand exitCommand = (BinaryExitCommand) readCommand;\n        assertEquals(42, exitCommand.getExitCode());\n        assertEquals(BinaryCommand.EXIT, exitCommand.getType());\n        assertTrue(exitCommand.isUrgent());\n    }\n    \n    @Test\n    public void testBinaryMessageCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        \n        // Create and write command\n        BinaryMessageCommand original = new BinaryMessageCommand(\"Test message\", true);\n        BinaryWireIO.write(baos, original);\n        \n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n        \n        // Verify command\n        assertTrue(readCommand instanceof BinaryMessageCommand);\n        BinaryMessageCommand msgCommand = (BinaryMessageCommand) readCommand;\n        assertEquals(\"Test message\", msgCommand.getMessage());\n        assertEquals(BinaryCommand.MESSAGE, msgCommand.getType());\n        assertEquals(original.isUrgent(), msgCommand.isUrgent());\n    }\n    \n    @Test\n    public void testBinaryMessageCommandWithCompression() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        \n        // Create a large message that will trigger compression\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < 2000; i++) {\n            sb.append(\"This is a test message that will be compressed. \");\n        }\n        String largeMessage = sb.toString();\n        \n        // Create and write command\n        BinaryMessageCommand original = new BinaryMessageCommand(largeMessage, true);\n        BinaryWireIO.write(baos, original);\n        \n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n        \n        // Verify command\n        assertTrue(readCommand instanceof BinaryMessageCommand);\n        BinaryMessageCommand msgCommand = (BinaryMessageCommand) readCommand;\n        assertEquals(largeMessage, msgCommand.getMessage());\n    }\n    \n    @Test\n    public void testBinaryInstrumentCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        \n        // Create test data\n        byte[] code = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};\n        Map<String, String> args = new HashMap<>();\n        args.put(\"key1\", \"value1\");\n        args.put(\"key2\", \"value2\");\n        \n        // Create and write command\n        BinaryInstrumentCommand original = new BinaryInstrumentCommand(code, args);\n        BinaryWireIO.write(baos, original);\n        \n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n        \n        // Verify command\n        assertTrue(readCommand instanceof BinaryInstrumentCommand);\n        BinaryInstrumentCommand instrCommand = (BinaryInstrumentCommand) readCommand;\n        assertArrayEquals(code, instrCommand.getCode());\n        ArgsMap readArgs = instrCommand.getArguments();\n        assertEquals(2, readArgs.size());\n        assertEquals(\"value1\", readArgs.get(\"key1\"));\n        assertEquals(\"value2\", readArgs.get(\"key2\"));\n    }\n    \n    @Test\n    public void testBinaryGridDataCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        \n        // Create test data\n        List<String> columnNames = new ArrayList<>();\n        columnNames.add(\"Column1\");\n        columnNames.add(\"Column2\");\n        columnNames.add(\"Column3\");\n        \n        List<Object[]> data = new ArrayList<>();\n        data.add(new Object[] { \"Row1Col1\", 123, 3.14 });\n        data.add(new Object[] { \"Row2Col1\", 456, 2.71 });\n        data.add(new Object[] { \"Row3Col1\", 789, \"Row3Col3\" });\n        \n        // Create and write command\n        BinaryGridDataCommand original = new BinaryGridDataCommand(\"TestGrid\", columnNames, data);\n        BinaryWireIO.write(baos, original);\n        \n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n        \n        // Verify command\n        assertTrue(readCommand instanceof BinaryGridDataCommand);\n        BinaryGridDataCommand gridCommand = (BinaryGridDataCommand) readCommand;\n        assertEquals(\"TestGrid\", gridCommand.getName());\n        \n        List<String> readColumnNames = gridCommand.getColumnNames();\n        assertEquals(3, readColumnNames.size());\n        assertEquals(\"Column1\", readColumnNames.get(0));\n        assertEquals(\"Column2\", readColumnNames.get(1));\n        assertEquals(\"Column3\", readColumnNames.get(2));\n        \n        List<Object[]> readData = gridCommand.getData();\n        assertEquals(3, readData.size());\n        assertEquals(\"Row1Col1\", readData.get(0)[0]);\n        assertEquals(123, readData.get(0)[1]);\n        assertEquals(3.14, readData.get(0)[2]);\n        assertEquals(\"Row2Col1\", readData.get(1)[0]);\n        assertEquals(456, readData.get(1)[1]);\n        assertEquals(2.71, readData.get(1)[2]);\n        assertEquals(\"Row3Col1\", readData.get(2)[0]);\n        assertEquals(789, readData.get(2)[1]);\n        assertEquals(\"Row3Col3\", readData.get(2)[2]);\n    }\n    \n    @Test\n    public void testCommandAdapter() throws IOException {\n        // Test command conversion from binary to original and back\n        BinaryExitCommand exitCmd = new BinaryExitCommand(42);\n        org.openjdk.btrace.core.comm.Command originalCmd = CommandAdapter.toBtraceCommand(exitCmd);\n        assertEquals(org.openjdk.btrace.core.comm.Command.EXIT, originalCmd.getType());\n\n        BinaryCommand convertedBack = CommandAdapter.toBinaryCommand(originalCmd);\n        assertTrue(convertedBack instanceof BinaryExitCommand);\n        assertEquals(42, ((BinaryExitCommand) convertedBack).getExitCode());\n    }\n\n    // Tests for the 13 previously untested command types\n\n    @Test\n    public void testBinaryErrorCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create and write command\n        BinaryErrorCommand original =\n            new BinaryErrorCommand(\n                \"java.lang.IllegalStateException\", \"Test error message\", \"stack-trace\");\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryErrorCommand);\n        BinaryErrorCommand errorCommand = (BinaryErrorCommand) readCommand;\n        assertEquals(\"java.lang.IllegalStateException\", errorCommand.getExceptionClass());\n        assertEquals(\"Test error message\", errorCommand.getMessage());\n        assertEquals(\"stack-trace\", errorCommand.getStackTrace());\n        assertEquals(BinaryCommand.ERROR, errorCommand.getType());\n    }\n\n    @Test\n    public void testBinaryErrorCommandNullMessage() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create and write command with null message\n        BinaryErrorCommand original = new BinaryErrorCommand(\"java.lang.RuntimeException\", null, null);\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryErrorCommand);\n        BinaryErrorCommand errorCommand = (BinaryErrorCommand) readCommand;\n        assertEquals(\"java.lang.RuntimeException\", errorCommand.getExceptionClass());\n        assertEquals(null, errorCommand.getMessage());\n        assertEquals(null, errorCommand.getStackTrace());\n    }\n\n    @Test\n    public void testBinaryEventCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create and write command\n        BinaryEventCommand original = new BinaryEventCommand(\"test.event.fired\");\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryEventCommand);\n        BinaryEventCommand eventCommand = (BinaryEventCommand) readCommand;\n        assertEquals(\"test.event.fired\", eventCommand.getEvent());\n        assertEquals(BinaryCommand.EVENT, eventCommand.getType());\n    }\n\n    @Test\n    public void testBinaryRenameCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create and write command\n        BinaryRenameCommand original = new BinaryRenameCommand(\"NewProbeName\");\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryRenameCommand);\n        BinaryRenameCommand renameCommand = (BinaryRenameCommand) readCommand;\n        assertEquals(\"NewProbeName\", renameCommand.getNewName());\n        assertEquals(BinaryCommand.RENAME, renameCommand.getType());\n    }\n\n    @Test\n    public void testBinaryStatusCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Test success status\n        BinaryStatusCommand original = new BinaryStatusCommand(1, true);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryStatusCommand);\n        BinaryStatusCommand statusCommand = (BinaryStatusCommand) readCommand;\n        assertEquals(1, statusCommand.getFlag());\n        assertTrue(statusCommand.isSuccess());\n        assertEquals(BinaryCommand.STATUS, statusCommand.getType());\n    }\n\n    @Test\n    public void testBinaryStatusCommandFailure() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Test failure status\n        BinaryStatusCommand original = new BinaryStatusCommand(2, false);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryStatusCommand);\n        BinaryStatusCommand statusCommand = (BinaryStatusCommand) readCommand;\n        assertEquals(2, statusCommand.getFlag());\n        assertTrue(!statusCommand.isSuccess());\n    }\n\n    @Test\n    public void testBinaryNumberMapDataCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create test data with various number types\n        Map<String, Number> data = new HashMap<>();\n        data.put(\"intValue\", 42);\n        data.put(\"longValue\", 9876543210L);\n        data.put(\"floatValue\", 3.14f);\n        data.put(\"doubleValue\", 2.71828);\n        data.put(\"bigIntValue\", new BigInteger(\"123456789012345678901234567890\"));\n        data.put(\"bigDecValue\", new BigDecimal(\"12345.67890123456789\"));\n\n        // Create and write command\n        BinaryNumberMapDataCommand original = new BinaryNumberMapDataCommand(\"TestNumberMap\", data);\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryNumberMapDataCommand);\n        BinaryNumberMapDataCommand mapCommand = (BinaryNumberMapDataCommand) readCommand;\n        assertEquals(\"TestNumberMap\", mapCommand.getName());\n        assertEquals(BinaryCommand.NUMBER_MAP, mapCommand.getType());\n\n        Map<String, Number> readData = mapCommand.getData();\n        assertEquals(6, readData.size());\n        assertEquals(42, readData.get(\"intValue\").intValue());\n        assertEquals(9876543210L, readData.get(\"longValue\").longValue());\n        assertEquals(3.14f, readData.get(\"floatValue\").floatValue(), 0.001);\n        assertEquals(2.71828, readData.get(\"doubleValue\").doubleValue(), 0.00001);\n        assertEquals(\n            new BigInteger(\"123456789012345678901234567890\"), readData.get(\"bigIntValue\"));\n        assertEquals(new BigDecimal(\"12345.67890123456789\"), readData.get(\"bigDecValue\"));\n    }\n\n    @Test\n    public void testBinaryNumberMapDataCommandEmpty() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create and write command with empty map\n        Map<String, Number> data = new HashMap<>();\n        BinaryNumberMapDataCommand original = new BinaryNumberMapDataCommand(\"EmptyMap\", data);\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryNumberMapDataCommand);\n        BinaryNumberMapDataCommand mapCommand = (BinaryNumberMapDataCommand) readCommand;\n        assertEquals(\"EmptyMap\", mapCommand.getName());\n        assertTrue(mapCommand.getData().isEmpty());\n    }\n\n    @Test\n    public void testBinaryStringMapDataCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create test data\n        Map<String, String> data = new HashMap<>();\n        data.put(\"key1\", \"value1\");\n        data.put(\"key2\", \"value2\");\n        data.put(\"key3\", \"value3\");\n\n        // Create and write command\n        BinaryStringMapDataCommand original = new BinaryStringMapDataCommand(\"TestStringMap\", data);\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryStringMapDataCommand);\n        BinaryStringMapDataCommand mapCommand = (BinaryStringMapDataCommand) readCommand;\n        assertEquals(\"TestStringMap\", mapCommand.getName());\n        assertEquals(BinaryCommand.STRING_MAP, mapCommand.getType());\n\n        Map<String, String> readData = mapCommand.getData();\n        assertEquals(3, readData.size());\n        assertEquals(\"value1\", readData.get(\"key1\"));\n        assertEquals(\"value2\", readData.get(\"key2\"));\n        assertEquals(\"value3\", readData.get(\"key3\"));\n    }\n\n    @Test\n    public void testBinaryNumberDataCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Test with Integer\n        BinaryNumberDataCommand original = new BinaryNumberDataCommand(\"TestInt\", 42);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryNumberDataCommand);\n        BinaryNumberDataCommand numberCommand = (BinaryNumberDataCommand) readCommand;\n        assertEquals(\"TestInt\", numberCommand.getName());\n        assertEquals(42, numberCommand.getValue().intValue());\n        assertEquals(BinaryCommand.NUMBER, numberCommand.getType());\n    }\n\n    @Test\n    public void testBinaryNumberDataCommandDouble() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Test with Double\n        BinaryNumberDataCommand original = new BinaryNumberDataCommand(\"TestDouble\", 3.14159);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryNumberDataCommand);\n        BinaryNumberDataCommand numberCommand = (BinaryNumberDataCommand) readCommand;\n        assertEquals(\"TestDouble\", numberCommand.getName());\n        assertEquals(3.14159, numberCommand.getValue().doubleValue(), 0.00001);\n    }\n\n    @Test\n    public void testBinaryNumberDataCommandLong() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Test with Long\n        BinaryNumberDataCommand original = new BinaryNumberDataCommand(\"TestLong\", 9876543210L);\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryNumberDataCommand);\n        BinaryNumberDataCommand numberCommand = (BinaryNumberDataCommand) readCommand;\n        assertEquals(\"TestLong\", numberCommand.getName());\n        assertEquals(9876543210L, numberCommand.getValue().longValue());\n    }\n\n    @Test\n    public void testBinaryNumberDataCommandBigDecimal() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Test with BigDecimal\n        BinaryNumberDataCommand original =\n            new BinaryNumberDataCommand(\"TestBigDecimal\", new BigDecimal(\"12345.67890123456789\"));\n        BinaryWireIO.write(baos, original);\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        assertTrue(readCommand instanceof BinaryNumberDataCommand);\n        BinaryNumberDataCommand numberCommand = (BinaryNumberDataCommand) readCommand;\n        assertEquals(\"TestBigDecimal\", numberCommand.getName());\n        assertEquals(new BigDecimal(\"12345.67890123456789\"), numberCommand.getValue());\n    }\n\n    @Test\n    public void testBinaryRetransformationStartNotification() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create and write command\n        BinaryRetransformationStartNotification original = new BinaryRetransformationStartNotification(150);\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryRetransformationStartNotification);\n        BinaryRetransformationStartNotification notification = (BinaryRetransformationStartNotification) readCommand;\n        assertEquals(150, notification.getNumClasses());\n        assertEquals(BinaryCommand.RETRANSFORMATION_START, notification.getType());\n    }\n\n    @Test\n    public void testBinaryRetransformClassNotification() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create and write command\n        BinaryRetransformClassNotification original = new BinaryRetransformClassNotification(\n            \"com.example.MyClass\", 10, 150\n        );\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryRetransformClassNotification);\n        BinaryRetransformClassNotification notification = (BinaryRetransformClassNotification) readCommand;\n        assertEquals(\"com.example.MyClass\", notification.getClassName());\n        assertEquals(10, notification.getIndex());\n        assertEquals(150, notification.getTotal());\n        assertEquals(BinaryCommand.RETRANSFORM_CLASS, notification.getType());\n    }\n\n    @Test\n    public void testBinarySetSettingsCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create test settings\n        Map<String, Object> settings = new HashMap<>();\n        settings.put(\"debug\", true);\n        settings.put(\"timeout\", 5000);\n        settings.put(\"threshold\", 1.5);\n        settings.put(\"name\", \"TestProbe\");\n\n        // Create and write command\n        BinarySetSettingsCommand original = new BinarySetSettingsCommand(settings);\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinarySetSettingsCommand);\n        BinarySetSettingsCommand settingsCommand = (BinarySetSettingsCommand) readCommand;\n        assertEquals(BinaryCommand.SET_PARAMS, settingsCommand.getType());\n\n        Map<String, Object> readSettings = settingsCommand.getParams();\n        assertEquals(4, readSettings.size());\n        assertEquals(true, readSettings.get(\"debug\"));\n        assertEquals(5000, readSettings.get(\"timeout\"));\n        assertEquals(1.5, ((Number) readSettings.get(\"threshold\")).doubleValue(), 0.001);\n        assertEquals(\"TestProbe\", readSettings.get(\"name\"));\n    }\n\n    @Test\n    public void testBinaryListProbesCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create test probe list\n        List<String> probes = new ArrayList<>();\n        probes.add(\"probe1\");\n        probes.add(\"probe2\");\n        probes.add(\"probe3\");\n\n        // Create and write command\n        BinaryListProbesCommand original = new BinaryListProbesCommand();\n        original.setProbes(probes);\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryListProbesCommand);\n        BinaryListProbesCommand listCommand = (BinaryListProbesCommand) readCommand;\n        assertEquals(BinaryCommand.LIST_PROBES, listCommand.getType());\n\n        List<String> readProbes = listCommand.getProbes();\n        assertEquals(3, readProbes.size());\n        assertEquals(\"probe1\", readProbes.get(0));\n        assertEquals(\"probe2\", readProbes.get(1));\n        assertEquals(\"probe3\", readProbes.get(2));\n    }\n\n    @Test\n    public void testBinaryListProbesCommandEmpty() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create and write command with empty list\n        BinaryListProbesCommand original = new BinaryListProbesCommand();\n        original.setProbes(new ArrayList<>());\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryListProbesCommand);\n        BinaryListProbesCommand listCommand = (BinaryListProbesCommand) readCommand;\n        assertTrue(listCommand.getProbes().isEmpty());\n    }\n\n    @Test\n    public void testBinaryDisconnectCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create and write command\n        BinaryDisconnectCommand original = new BinaryDisconnectCommand(\"probe-12345\");\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryDisconnectCommand);\n        BinaryDisconnectCommand disconnectCommand = (BinaryDisconnectCommand) readCommand;\n        assertEquals(\"probe-12345\", disconnectCommand.getProbeId());\n        assertEquals(BinaryCommand.DISCONNECT, disconnectCommand.getType());\n    }\n\n    @Test\n    public void testBinaryReconnectCommand() throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n\n        // Create and write command\n        BinaryReconnectCommand original = new BinaryReconnectCommand(\"probe-67890\");\n        BinaryWireIO.write(baos, original);\n\n        // Read command\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryCommand readCommand = BinaryWireIO.read(bais);\n\n        // Verify command\n        assertTrue(readCommand instanceof BinaryReconnectCommand);\n        BinaryReconnectCommand reconnectCommand = (BinaryReconnectCommand) readCommand;\n        assertEquals(\"probe-67890\", reconnectCommand.getProbeId());\n        assertEquals(BinaryCommand.RECONNECT, reconnectCommand.getType());\n    }\n} \n"
  },
  {
    "path": "btrace-dist/build.gradle",
    "content": "plugins {\n    id 'java'\n    id 'maven-publish'\n    id 'signing'\n    alias(libs.plugins.shadow)\n    alias(libs.plugins.ospackage)\n    alias(libs.plugins.sdkman.vendors)\n}\n\nimport com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar\nimport org.gradle.internal.os.OperatingSystem\n\nrepositories {\n    mavenCentral()\n}\n\ndef distBase = \"${project.buildDir}/resources/main\"\ndef distTarget = \"${distBase}/v${project.version}\"\ndef libsDir = new File(\"${distTarget}/libs\")\n\ndef includes = [:]\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(8))\n    }\n}\n\nincludes['agent'] = {\n    if (it.directory) {\n        return true\n    }\n    if (it.path.endsWith('.jar')) {\n        return true\n    }\n    return it.path.startsWith('org/jctools/') ||\n            it.path.startsWith('org/openjdk/btrace/agent/') ||\n            it.path.startsWith('org/openjdk/btrace/instr/') ||\n            it.path.startsWith('org/openjdk/btrace/runtime/') ||\n            it.path.startsWith('org/openjdk/btrace/extension/') ||\n            it.path.startsWith('org/openjdk/btrace/core/comm/') ||\n            it.path.startsWith('org/openjdk/btrace/core/handlers/') ||\n            // core/extensions moved to shared section\n            // include the messages resource bundle and class in the agent jar (bootstrap can't load resources)\n            it.path == 'org/openjdk/btrace/core/Messages.class' ||\n            it.path == 'org/openjdk/btrace/core/messages.properties'\n}\n\nincludes['boot'] = {\n    if (it.directory) {\n        return true\n    }\n    if (it.path.endsWith('.jar')) {\n        return true\n    }\n    if (it.path.startsWith('org/openjdk/btrace/core/')) {\n        if (it.path == 'org/openjdk/btrace/core/Messages.class' || it.path == 'org/openjdk/btrace/core/messages.properties') {\n            // messages resource bundle&class are hoisted to agent and client jars\n            return false\n        }\n        return true\n    }\n    if (it.path.startsWith('org/objectweb/asm/')) {\n        if (it.path.startsWith('org/objectweb/asm/commons/') ||\n                it.path.startsWith('org/objectweb/asm/util/') ||\n                it.path.startsWith('org/objectweb/asm/xml/')) {\n            return false\n        }\n        return true\n    }\n    if (it.path.startsWith('META-INF/services')) {\n        return !it.path.contains('com.sun.') && !it.path.contains('javax.annotation.')\n    }\n    // btrace-runtime classes should ONLY be in .classdata form (agent section), not as regular .class files\n    return it.path.startsWith(\"org/slf4j/\") ||\n            it.path.startsWith('org/openjdk/btrace/extension/') ||\n            it.path.startsWith('org/jctools/')\n            // Extensions are loaded from extensions/ directory\n}\n\nincludes['client'] = {\n    if (it.directory) {\n        return true\n    }\n    if (it.path.endsWith('.jar')) {\n        return true\n    }\n    if (it.path.startsWith('org/openjdk/btrace')) {\n        return !it.path.startsWith('org/openjdk/btrace/agent')\n    }\n    if (it.path.startsWith('com/googlecode/lanterna/')) {\n        return true\n    }\n    if (it.path.startsWith('META-INF/services')) {\n        return !it.path.contains('com.sun.') && !it.path.contains('javax.annotation.')\n    }\n    return it.path.startsWith(\"org/slf4j\") ||\n            it.path.startsWith('org/objectweb/asm') ||\n            it.path.startsWith('org/jctools')\n}\n\n\nconfigurations {\n    artifact.extendsFrom implementation\n}\n\ndependencies {\n    implementation project(':btrace-agent')\n    implementation project(':btrace-client')\n    implementation project(':btrace-compiler')\n    // Metrics extension excluded unless present; extensions copied dynamically\n    implementation project(':btrace-ext-cli')\n}\n\njar {\n    onlyIf { false }  // Disable default jar task\n}\n\nsourcesJar {\n    onlyIf { false }\n}\n\nsourceSets {\n    main {\n        output.resourcesDir = file(\"${distTarget}\")\n    }\n}\nartifacts {\n    archives file(\"${distTarget}/libs/btrace.jar\")\n}\n\n// Intermediate shadow jar with all dependencies and relocations\n// This is NOT an output artifact, just used for building the masked jar\ntask allClassesShadow(type: ShadowJar) {\n    group 'Build'\n    archiveBaseName.set('btrace-all-temp')\n    archiveVersion.set('')\n    archiveClassifier.set('shadow')\n    destinationDirectory = file(\"${project.buildDir}/tmp\")\n\n    configurations = [project.configurations.artifact]\n\n    // Relocate dependencies\n    relocate 'org.jctools', 'org.openjdk.btrace.libs.org.jctools'\n    relocate 'org.objectweb.asm', 'org.openjdk.btrace.libs.org.objectweb.asm'\n    relocate 'org.slf4j', 'org.openjdk.btrace.libs.org.slf4j'\n\n    // Don't create a manifest for this intermediate jar\n    manifest {\n        attributes([:])\n    }\n}\n\ntask apiJar(type: Jar) {\n    group 'Build'\n    description 'Creates API JAR for compile-time dependencies'\n    archiveBaseName.set('btrace-api')\n    archiveVersion.set('')\n    archiveClassifier.set('')\n    destinationDirectory = libsDir\n\n    from(project(':btrace-api').sourceSets.main.output)\n}\n\n// uberJar removed - btrace.jar (masked jar) is the single source of truth\n\n// ==================== Masked JAR ====================\n// Single JAR with .classdata masking for bootstrap isolation\n// Bootstrap classes are stored as .class, non-bootstrap as .classdata\n// Uses existing shadow JARs to get properly relocated classes\n\ndef maskedJarTmpDir = new File(project.buildDir, \"masked-jar-tmp\")\n\n// Task to prepare agent classes with .classdata extension\ntask prepareAgentClassdata(type: Copy) {\n    group 'Build'\n    description 'Prepare agent classes with .classdata extension'\n    dependsOn allClassesShadow, processResources\n\n    into \"${maskedJarTmpDir}/agent\"\n\n    from(provider { zipTree(allClassesShadow.archiveFile) }) {\n        include 'org/openjdk/btrace/libs/org/jctools/**/*.class'\n        include 'org/openjdk/btrace/agent/**/*.class'\n        include 'org/openjdk/btrace/instr/**/*.class'\n        include 'org/openjdk/btrace/instr/jaxb.index'  // Required for JAXB probe descriptor loading\n        include 'org/openjdk/btrace/runtime/**/*.class'\n        include 'org/openjdk/btrace/extension/**/*.class'\n        include 'org/openjdk/btrace/core/comm/**/*.class'\n        include 'org/openjdk/btrace/core/handlers/**/*.class'\n        include 'org/openjdk/btrace/core/Messages.class'\n        include 'org/openjdk/btrace/core/messages.properties'\n        // Exclude classes that go in shared section\n        exclude 'org/openjdk/btrace/core/extensions/**'\n        exclude 'org/openjdk/btrace/core/annotations/**'\n        // Exclude bootstrap runtime classes (now in btrace-core)\n        exclude 'org/openjdk/btrace/runtime/BTraceRuntimeAccess.class'\n        exclude 'org/openjdk/btrace/runtime/BTraceRuntimeAccess$*.class'\n        exclude 'org/openjdk/btrace/runtime/LinkingFlag.class'\n        exclude 'META-INF/**'\n        rename { name -> name.endsWith('.class') ? name.replace('.class', '.classdata') : name }\n    }\n\n    duplicatesStrategy = DuplicatesStrategy.EXCLUDE\n}\n\n// Task to prepare client classes with .classdata extension\ntask prepareClientClassdata(type: Copy) {\n    group 'Build'\n    description 'Prepare client classes with .classdata extension'\n    dependsOn allClassesShadow, processResources\n\n    into \"${maskedJarTmpDir}/client\"\n\n    from(provider { zipTree(allClassesShadow.archiveFile) }) {\n        include 'org/openjdk/btrace/client/**/*.class'\n        include 'org/openjdk/btrace/compiler/**/*.class'\n        include 'org/openjdk/btrace/libs/org/jctools/**/*.class'\n        include 'com/googlecode/lanterna/**/*.class'\n        // Exclude classes that are in bootstrap or shared\n        exclude 'org/openjdk/btrace/core/**'\n        exclude 'org/openjdk/btrace/runtime/**'\n        exclude 'org/openjdk/btrace/extension/**'\n        exclude 'org/openjdk/btrace/libs/org/objectweb/asm/**'\n        exclude 'org/openjdk/btrace/libs/org/slf4j/**'\n        exclude 'META-INF/**'\n        rename { name -> name.endsWith('.class') ? name.replace('.class', '.classdata') : name }\n    }\n\n    // Messages is excluded from the core/** block above but is required by Main.usage().\n    // It cannot be in bootstrap (Messages.class.getClassLoader() would return null there,\n    // breaking ResourceBundle.getBundle()), so it must be in the client masked section.\n    from(provider { zipTree(allClassesShadow.archiveFile) }) {\n        include 'org/openjdk/btrace/core/Messages.class'\n        include 'org/openjdk/btrace/core/messages.properties'\n        rename { name -> name.endsWith('.class') ? name.replace('.class', '.classdata') : name }\n    }\n\n    duplicatesStrategy = DuplicatesStrategy.EXCLUDE\n}\n\n// Task to prepare shared classes with .classdata extension (used by both agent and client)\ntask prepareSharedClassdata(type: Copy) {\n    group 'Build'\n    description 'Prepare shared classes with .classdata extension (for both agent and client)'\n    dependsOn allClassesShadow, processResources\n\n    into \"${maskedJarTmpDir}/shared\"\n\n    from(provider { zipTree(allClassesShadow.archiveFile) }) {\n        // Only include classes used by both client and agent\n        include 'org/openjdk/btrace/core/comm/**/*.class'\n        include 'org/openjdk/btrace/core/extensions/**/*.class'\n        include 'org/openjdk/btrace/core/annotations/**/*.class'\n        include 'org/openjdk/btrace/libs/org/objectweb/asm/**/*.class'\n        // Exclude ASM packages not needed\n        exclude 'org/openjdk/btrace/libs/org/objectweb/asm/commons/**'\n        exclude 'org/openjdk/btrace/libs/org/objectweb/asm/util/**'\n        exclude 'org/openjdk/btrace/libs/org/objectweb/asm/xml/**'\n        exclude 'META-INF/**'\n        rename { name -> name.endsWith('.class') ? name.replace('.class', '.classdata') : name }\n    }\n\n    duplicatesStrategy = DuplicatesStrategy.EXCLUDE\n}\n\n// Single JAR with .classdata masking for bootstrap isolation\ntask btraceJar(type: Jar) {\n    group 'Build'\n    description 'Creates single JAR with .classdata masking for bootstrap isolation'\n    archiveBaseName.set('btrace')\n    archiveVersion.set('')\n    archiveClassifier.set('')\n    destinationDirectory = libsDir\n\n    dependsOn prepareAgentClassdata, prepareClientClassdata, prepareSharedClassdata\n    dependsOn project(':btrace-boot').tasks.jar\n    dependsOn project(':btrace-bootstrap').tasks.shadowJar\n\n    // 1. Include boot loader class (must be in bootstrap as .class)\n    from(project(':btrace-boot').sourceSets.main.output) {\n        include 'org/openjdk/btrace/boot/**/*.class'\n    }\n\n    // 2. Include bootstrap classes from btrace-bootstrap shadowJar (as .class)\n    from(zipTree(project(':btrace-bootstrap').tasks.shadowJar.archiveFile)) {\n        include '**/*.class'\n        include 'META-INF/services/**'\n        include '**/jaxb.index'  // Required for JAXB probe descriptor loading\n        exclude 'org/openjdk/btrace/core/comm/**'\n        // Include annotations in bootstrap (needed by ExtensionIndy at runtime)\n        // Exclude manifest from bootstrap jar\n        exclude 'META-INF/MANIFEST.MF'\n    }\n\n    // 3. Include masked agent classes (as .classdata)\n    into('META-INF/btrace/agent') {\n        from(\"${maskedJarTmpDir}/agent\") {\n            include '**/*.classdata'\n            include '**/messages.properties'\n            include '**/jaxb.index'  // Required for JAXB probe descriptor loading\n        }\n    }\n\n    // 4. Include masked client classes (as .classdata)\n    into('META-INF/btrace/client') {\n        from(\"${maskedJarTmpDir}/client\") {\n            include '**/*.classdata'\n            include '**/messages.properties'\n        }\n    }\n\n    // 5. Include shared classes (as .classdata) - used by both agent and client\n    into('META-INF/btrace/shared') {\n        from(\"${maskedJarTmpDir}/shared\") {\n            include '**/*.classdata'\n        }\n    }\n\n    // 6. Include extensions in root (needed by bootstrap)\n    // Note: Messages class is NOT included in bootstrap - it uses ResourceBundle.getBundle()\n    // with Messages.class.getClassLoader() which returns null for bootstrap classes,\n    // causing NPE. Messages is only in agent/client sections where classloader is non-null.\n    from(project(':btrace-core').sourceSets.main.output) {\n        include 'org/openjdk/btrace/core/extensions/**/*.class'\n    }\n\n    manifest {\n        attributes(\n            'Premain-Class': 'org.openjdk.btrace.boot.Loader',\n            'Agent-Class': 'org.openjdk.btrace.boot.Loader',\n            'Main-Class': 'org.openjdk.btrace.boot.Loader',\n            'Can-Redefine-Classes': true,\n            'Can-Retransform-Classes': true,\n            'Boot-Class-Path': 'btrace.jar',\n            'BTrace-Version': version,\n            'BTrace-Agent-Main': 'org.openjdk.btrace.agent.Main',\n            'BTrace-Client-Main': 'org.openjdk.btrace.client.Main'\n        )\n    }\n\n    duplicatesStrategy = DuplicatesStrategy.EXCLUDE\n}\n\ntask fixPermissions(type: Exec) {\n    onlyIf {\n        !OperatingSystem.current().isWindows()\n    }\n    commandLine 'chmod', '500', \"${distTarget}/bin/btrace\"\n    commandLine 'chmod', '500', \"${distTarget}/bin/btracec\"\n    commandLine 'chmod', '500', \"${distTarget}/bin/btracer\"\n    commandLine 'chmod', '500', \"${distTarget}/bin/btracex\"\n\n    dependsOn processResources\n}\n\ntask copyDtraceLib(type: Copy) {\n    from \"${projectDir}/../btrace-dtrace/build/dtrace/libs\"\n    into \"${distTarget}/libs/\"\n}\n\ntask copyExtensions(type: Copy) {\n    group 'Build'\n    description 'Copy extension ZIP archives to extensions/ directory'\n    into \"${distTarget}/extensions/\"\n}\n\n// Copy the btracex CLI shaded jar into libs\n\n// Discover all extension subprojects and wire copyExtensions dynamically to avoid hard-coded paths\ngradle.projectsEvaluated {\n    def extProjects = rootProject.subprojects.findAll { it.plugins.hasPlugin('org.openjdk.btrace.extension') }\n    if (extProjects.isEmpty()) {\n        logger.lifecycle(\"[btrace-dist] No BTrace extension projects found. Skipping extension packaging.\")\n    } else {\n        tasks.named('copyExtensions').configure { t ->\n            extProjects.each { sp ->\n                // Depend on packaging task and copy any *-extension.zip from its distributions folder\n                t.dependsOn(\"${sp.path}:packageExtension\")\n                t.from(sp.layout.buildDirectory.dir('distributions')) {\n                    include \"*-extension.zip\"\n                }\n            }\n        }\n    }\n}\n\ntask explodeExtensions {\n    group 'Build'\n    description 'Explode extension ZIP archives into extension subdirectories'\n    dependsOn copyExtensions\n\n    doLast {\n        def extensionsDir = file(\"${distTarget}/extensions\")\n        if (!extensionsDir.exists()) {\n            return\n        }\n\n        extensionsDir.listFiles().each { file ->\n            if (file.name.endsWith('-extension.zip')) {\n                // Extract extension name from filename: btrace-metrics-2.3.0-SNAPSHOT-extension.zip -> btrace-metrics\n                def extensionName = file.name.replaceAll(/-\\d+.*-extension\\.zip$/, '')\n                def targetDir = new File(extensionsDir, extensionName)\n                targetDir.mkdirs()\n\n                // Explode ZIP into extension directory\n                copy {\n                    from zipTree(file)\n                    into targetDir\n                }\n\n                logger.info(\"Exploded extension ${file.name} into ${extensionName}/\")\n            }\n        }\n    }\n}\n\ntask buildZip(type: Zip) {\n    dependsOn btraceJar, fixPermissions, explodeExtensions\n    from \"${distTarget}\"\n    include \"**/*\"\n\n    archiveBaseName.set('btrace')\n    archiveVersion.set(\"v${project.version}\")\n    archiveClassifier.set(\"bin\")\n    destinationDirectory = new File(project.buildDir, \"distributions\")\n}\n\ntask buildSdkmanZip(type: Zip) {\n    from \"${distBase}\"\n    include \"**/*\"\n\n    archiveBaseName.set('btrace')\n    archiveVersion.set(\"v${project.version}\")\n    archiveClassifier.set(\"sdkman-bin\")\n    destinationDirectory = new File(project.buildDir, \"distributions\")\n}\n\ntask buildTgz(type: Tar) {\n    into ('/'){\n        from \"${distTarget}\"\n        include '**/*'\n    }\n\n    archiveBaseName.set('btrace')\n    archiveVersion.set(\"v${project.version}\")\n    archiveClassifier.set(\"bin\")\n    destinationDirectory = new File(project.buildDir, \"distributions\")\n    archiveExtension.set('tar.gz')\n    compression = Compression.GZIP\n}\n\nospackage {\n    packageName = 'btrace'\n    release = 1\n    os = LINUX\n\n    into '/opt/btrace'\n\n    from(\"${distTarget}/bin\") {\n        into 'bin'\n        fileMode 0550\n    }\n\n    from(\"${distTarget}/libs\") {\n        into 'libs'\n    }\n\n    from(\"${distTarget}/docs\") {\n        into 'docs'\n    }\n\n    from(\"${distTarget}/samples\") {\n        into 'samples'\n    }\n\n    link('/usr/local/bin/btrace', '/opt/btrace/bin/btrace')\n    link('/usr/local/bin/btracer', '/opt/btrace/bin/btracer')\n    link('/usr/local/bin/btracec', '/opt/btrace/bin/btracec')\n    link('/usr/local/bin/btracex', '/opt/btrace/bin/btracex')\n}\n\nbuildDeb {\n    requires('openjdk-8-jdk')\n}\n\ncopyDtraceLib.dependsOn project(':btrace-dtrace').build\nshadowJar.dependsOn btraceJar, apiJar, copyDtraceLib, copyExtensions\nbuildTgz.dependsOn btraceJar, apiJar, fixPermissions, copyDtraceLib, processResources, explodeExtensions\nbuildZip.dependsOn btraceJar, apiJar, fixPermissions, copyDtraceLib, processResources, explodeExtensions\nbuildSdkmanZip.dependsOn btraceJar, apiJar, fixPermissions, copyDtraceLib, processResources, explodeExtensions\nbuildDeb.dependsOn btraceJar, apiJar, fixPermissions, copyDtraceLib, processResources, explodeExtensions\nbuildRpm.dependsOn btraceJar, apiJar, fixPermissions, copyDtraceLib, processResources, explodeExtensions\nbuild.dependsOn buildSdkmanZip, buildZip, buildTgz, buildDeb, buildRpm\n\n// Docker build tasks\ntask buildDockerContext(type: Copy, dependsOn: [btraceJar, apiJar, copyDtraceLib, processResources, fixPermissions]) {\n    group 'Docker'\n    description 'Prepare Docker build context with BTrace distribution'\n\n    from \"${distTarget}\"\n    into \"${buildDir}/docker-context/btrace\"\n    fileMode = 0644\n\n    doLast {\n        // Copy entrypoint script\n        copy {\n            from \"${projectDir}/../docker/docker-entrypoint.sh\"\n            into \"${buildDir}/docker-context\"\n        }\n        // Copy .dockerignore to build context so Docker can use it\n        copy {\n            from \"${projectDir}/../docker/.dockerignore\"\n            into \"${buildDir}/docker-context\"\n        }\n    }\n}\n\ntask buildDockerImage(type: Exec, dependsOn: buildDockerContext) {\n    group 'Docker'\n    description 'Build main Debian-based Docker image'\n\n    onlyIf {\n        project.hasProperty('dockerEnabled') &&\n        (project.hasProperty('dockerBuildx') ?\n            'docker buildx version'.execute().waitFor() == 0 :\n            'docker --version'.execute().waitFor() == 0)\n    }\n\n    workingDir \"${projectDir}/../docker\"\n\n    def buildArgs = [\n        'docker', 'build',\n        '--build-arg', \"BTRACE_VERSION=${project.version}\",\n        '-t', \"btrace/btrace:${project.version}\",\n        '-t', \"btrace/btrace:latest\",\n        '-f', 'Dockerfile',\n        \"${buildDir}/docker-context\"\n    ]\n\n    if (project.hasProperty('dockerBuildx')) {\n        buildArgs.add(1, 'buildx')\n        buildArgs.addAll(['--platform', 'linux/amd64,linux/arm64'])\n    }\n\n    commandLine buildArgs\n}\n\ntask buildDockerImageAlpine(type: Exec, dependsOn: buildDockerContext) {\n    group 'Docker'\n    description 'Build Alpine-based Docker image'\n\n    onlyIf {\n        project.hasProperty('dockerEnabled') &&\n        (project.hasProperty('dockerBuildx') ?\n            'docker buildx version'.execute().waitFor() == 0 :\n            'docker --version'.execute().waitFor() == 0)\n    }\n\n    workingDir \"${projectDir}/../docker\"\n\n    def buildArgs = [\n        'docker', 'build',\n        '--build-arg', \"BTRACE_VERSION=${project.version}\",\n        '-t', \"btrace/btrace:${project.version}-alpine\",\n        '-t', \"btrace/btrace:latest-alpine\",\n        '-f', 'Dockerfile.alpine',\n        \"${buildDir}/docker-context\"\n    ]\n\n    if (project.hasProperty('dockerBuildx')) {\n        buildArgs.add(1, 'buildx')\n        buildArgs.addAll(['--platform', 'linux/amd64,linux/arm64'])\n    }\n\n    commandLine buildArgs\n}\n\ntask buildDockerImageDistroless(type: Exec, dependsOn: buildDockerContext) {\n    group 'Docker'\n    description 'Build distroless Docker image'\n\n    onlyIf {\n        project.hasProperty('dockerEnabled') &&\n        (project.hasProperty('dockerBuildx') ?\n            'docker buildx version'.execute().waitFor() == 0 :\n            'docker --version'.execute().waitFor() == 0)\n    }\n\n    workingDir \"${projectDir}/../docker\"\n\n    def buildArgs = [\n        'docker', 'build',\n        '--build-arg', \"BTRACE_VERSION=${project.version}\",\n        '-t', \"btrace/btrace:${project.version}-distroless\",\n        '-t', \"btrace/btrace:latest-distroless\",\n        '-f', 'Dockerfile.distroless',\n        file(\"${buildDir}/docker-context\").absolutePath\n    ]\n\n    if (project.hasProperty('dockerBuildx')) {\n        buildArgs.add(1, 'buildx')\n        buildArgs.addAll(['--platform', 'linux/amd64'])\n    }\n\n    commandLine buildArgs\n}\n\ntask buildDockerImages {\n    group 'Docker'\n    description 'Build all Docker image variants'\n    dependsOn buildDockerImage, buildDockerImageAlpine, buildDockerImageDistroless\n}\n\ntest {\n    doLast {\n        project(':btrace-instr').tasks.test.execute()\n    }\n}\n\n['agent', 'boot', 'client'].each { name ->\n    // Define a temporary directory for the sources\n    def tempDir = new File(buildDir, \"tmp/${name}Sources\")\n\n    // first, we will copy the classes and make sure there are no empty directories\n    tasks.create(name: \"${name}CopySources\", type: Copy) {\n        doFirst {\n            tempDir.deleteDir()  // Ensure the directory is clean\n        }\n\n        into tempDir\n\n        duplicatesStrategy = DuplicatesStrategy.EXCLUDE\n        gradle.projectsEvaluated {\n            rootProject.childProjects.each { projectName, siblingProject ->\n                // Skip the current project to avoid duplication\n                if (siblingProject != project) {\n                    from(siblingProject.sourceSets.main.allSource) {\n                        include includes[\"${name}\"]\n                        exclude 'META-INF/**'\n                    }\n                }\n            }\n        }\n\n        doLast {\n            // Recursively delete empty directories\n            def deleteEmptyDirs\n            deleteEmptyDirs = { dir ->\n                dir.eachDir { subDir ->\n                    deleteEmptyDirs(subDir)\n                    if (!subDir.listFiles().any()) {\n                        subDir.deleteDir()\n                    }\n                }\n            }\n            deleteEmptyDirs(tempDir)\n        }\n    }\n\n    // we will use the output of the previous task to crate the JAR\n    tasks.create(name: \"${name}SourcesJar\", type: Jar, dependsOn: \"${name}CopySources\") {\n        group 'Documentation'\n        description \"Build the btrace-${name} sources jar.\"\n\n        archiveAppendix = \"${name}\"\n        archiveClassifier = \"sources\"\n        duplicatesStrategy = DuplicatesStrategy.EXCLUDE\n\n        from tempDir\n    }\n\n    tasks.create(name: \"${name}Javadoc\", type: Javadoc) {\n        group 'Documentation'\n        description \"Generates Javadoc API documentation for the btrace-${name}.\"\n\n        title = \"btrace-${name}\"\n        destinationDir = file(\"${project.docsDir}/${name}/javadoc\")\n        classpath = files(compileJava.destinationDirectory) + configurations.artifact.asFileTree\n        options.addStringOption('Xdoclint:all,-missing', '-quiet')\n        failOnError false\n\n        project.parent.subprojects.each { subproject ->\n            // Skip the current project to avoid duplication\n            if (subproject != project) {\n                // Add source from sibling projects based on filter\n                source subproject.sourceSets.main.java.matching {\n                    include includes[\"${name}\"]\n                }\n            }\n        }\n\n        // Include classpath of all sibling projects\n        project.parent.subprojects.each { subproject ->\n            // Skip the current project to avoid duplication\n            if (subproject != project) {\n                classpath += subproject.sourceSets.main.compileClasspath\n            }\n        }\n    }\n\n\n    tasks.create(name: \"${name}JavadocJar\", type: Jar) {\n        group 'Documentation'\n        description \"Build the btrace-${name} javadoc jar.\"\n\n        archiveAppendix = \"${name}\"\n        archiveClassifier = \"javadoc\"\n        from tasks[\"${name}Javadoc\"].getOutputs()\n    }\n}\n\nsdkman {\n    consumerKey = project.hasProperty(\"sdkman.key\") ? project.property(\"sdkman.key\") : System.getenv('SDKMAN_KEY')\n    consumerToken = project.hasProperty(\"sdkman.token\") ? project.property(\"sdkman.token\") : System.getenv('SDKMAN_TOKEN')\n    candidate = \"btrace\"\n    version = \"${project.version}\"\n    url = \"https://github.com/btraceio/btrace/releases/download/v${project.version}/btrace-v${project.version}-sdkman-bin.zip\"\n    hashtag = \"btrace\"\n}\n\n[\"sdkReleaseVersion\", \"sdkAnnounceVersion\"].forEach {\n    tasks[it].onlyIf {\n        !project.version.toString().endsWith(\"-SNAPSHOT\")\n    }\n}\n\npublishing {\n    repositories {\n        maven {\n            // Central Portal URLs (OSSRH was sunset on June 30, 2025)\n            def releasesRepoUrl = \"https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/\"\n            def snapshotsRepoUrl = \"https://central.sonatype.com/repository/maven-snapshots/\"\n            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl\n\n            credentials {\n                // Use Central Portal user token credentials\n                username = project.hasProperty(\"sonatype.user\") ? project.property(\"sonatype.user\") : System.getenv('SONATYPE_USER')\n                password = project.hasProperty(\"sonatype.password\") ? project.property(\"sonatype.password\") : System.getenv('SONATYPE_PASSWORD')\n            }\n        }\n    }\n\n    publications {\n        btrace(MavenPublication) {\n            artifactId 'btrace'\n            groupId 'io.btrace'\n            artifact btraceJar\n            pom.withXml {\n                addPomDetails(asNode(), 'btrace')\n            }\n        }\n    }\n}\n\ndef addPomDetails(node, name) {\n    node.appendNode('name', name)\n    node.appendNode('url', 'https://github.com/btraceio/btrace')\n    node.appendNode('description', 'BTrace: A safe, dynamic tracing tool for the Java platform')\n    def scmNode = node.appendNode('scm')\n    scmNode.appendNode('url', 'https://github.com/btraceio/btrace')\n    scmNode.appendNode('connection', 'scm:git:https://github.com/btraceio/btrace.git')\n    scmNode.appendNode('developerConnection', 'scm:git:https://github.com/btraceio/btrace.git')\n\n    def licenseNode = node.appendNode('licenses').appendNode('license')\n    licenseNode.appendNode('name', 'GNU General Public License, version 2, with the Classpath Exception')\n    licenseNode.appendNode('url', 'http://openjdk.java.net/legal/gplv2+ce.html')\n\n    def developerNode = node.appendNode('developers').appendNode('developer')\n    developerNode.appendNode('id', 'jbachorik')\n    developerNode.appendNode('name', 'Jaroslav Bachorik')\n    developerNode.appendNode('email', 'j.bachorik@btrace.io')\n}\n\nsigning {\n    def signingKey = project.hasProperty('gpg.signing.key') ? project.property('gpg.signing.key') : System.getenv(\"GPG_SIGNING_KEY\")\n    def signingPwd = project.hasProperty('gpg.signing.pwd') ? project.property('gpg.signing.pwd') : System.getenv(\"GPG_SIGNING_PWD\")\n\n    if (signingKey != null && signingPwd != null) {\n        useInMemoryPgpKeys(signingKey, signingPwd)\n    }\n    sign publishing.publications.btrace\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/COPYRIGHT",
    "content": "Copyright  2008 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, California 95054, U.S.A. All rights reserved.\n\nSun Microsystems, Inc. has intellectual property rights relating to technology embodied in the product that is described in this document. In particular, and without limitation, these intellectual property rights may include one or more of the U.S. patents listed at http://www.sun.com/patents and one or more additional patents or pending patent applications in the U.S. and in other countries.\n\nU.S. Government Rights - Commercial software. Government users are subject to the Sun Microsystems, Inc. standard license agreement and applicable provisions of the FAR and its supplements.\n\nUse is subject to license terms.\n\nThis distribution may include materials developed by third parties.\n\nSun, Sun Microsystems, the Sun logo, Java, Jini, Solaris and BTrace are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries.\n\nThis product is covered and controlled by U.S. Export Control laws and may be subject to the export or import laws in other countries. Nuclear, missile, chemical biological weapons or nuclear maritime end uses or end users, whether direct or indirect, are strictly prohibited. Export or reexport to countries subject to U.S. embargo or to entities identified on U.S. export exclusion lists, including, but not limited to, the denied persons and specially designated nationals lists is strictly prohibited.\n\n\nCopyright  2008 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, California 95054, Etats-Unis. Tous droits rservs.\n\nSun Microsystems, Inc. dtient les droits de proprit intellectuels relatifs  la technologie incorpore dans le produit qui est dcrit dans ce document. En particulier, et ce sans limitation, ces droits de proprit intellectuelle peuvent inclure un ou plus des brevets amricains lists  l'adresse http://www.sun.com/patents et un ou les brevets supplmentaires ou les applications de brevet en attente aux Etats - Unis et dans les autres pays.\n\nL'utilisation est soumise aux termes de la Licence.\n\nCette distribution peut comprendre des composants dvelopps par des tierces parties.\n\nSun, Sun Microsystems, le logo Sun, Java, Jini, Solaris et BTrace sont des marques de fabrique ou des marques dposes de Sun Microsystems, Inc. aux Etats-Unis et dans d'autres pays.\n\nCe produit est soumis  la lgislation amricaine en matire de contrle des exportations et peut tre soumis  la rglementation en vigueur dans d'autres pays dans le domaine des exportations et importations. Les utilisations, ou utilisateurs finaux, pour des armes nuclaires,des missiles, des armes biologiques et chimiques ou du nuclaire maritime, directement ou indirectement, sont strictement interdites. Les exportations ou rexportations vers les pays sous embargo amricain, ou vers des entits figurant sur les listes d'exclusion d'exportation amricaines, y compris, mais de manire non exhaustive, la liste de personnes qui font objet d'un ordre de ne pas participer, d'une faon directe ou indirecte, aux exportations des produits ou des services qui sont rgis par la lgislation amricaine en matire de contrle des exportations et la liste de ressortissants spcifiquement dsigns, sont rigoureusement interdites.\n\n"
  },
  {
    "path": "btrace-dist/src/main/resources/LICENSE",
    "content": "The GNU General Public License (GPL)\n\nVersion 2, June 1991\n\nCopyright (C) 1989, 1991 Free Software Foundation, Inc.\n59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\nEveryone is permitted to copy and distribute verbatim copies of this license\ndocument, but changing it is not allowed.\n\nPreamble\n\nThe licenses for most software are designed to take away your freedom to share\nand change it.  By contrast, the GNU General Public License is intended to\nguarantee your freedom to share and change free software--to make sure the\nsoftware is free for all its users.  This General Public License applies to\nmost of the Free Software Foundation's software and to any other program whose\nauthors commit to using it.  (Some other Free Software Foundation software is\ncovered by the GNU Library General Public License instead.) You can apply it to\nyour programs, too.\n\nWhen we speak of free software, we are referring to freedom, not price.  Our\nGeneral Public Licenses are designed to make sure that you have the freedom to\ndistribute copies of free software (and charge for this service if you wish),\nthat you receive source code or can get it if you want it, that you can change\nthe software or use pieces of it in new free programs; and that you know you\ncan do these things.\n\nTo protect your rights, we need to make restrictions that forbid anyone to deny\nyou these rights or to ask you to surrender the rights.  These restrictions\ntranslate to certain responsibilities for you if you distribute copies of the\nsoftware, or if you modify it.\n\nFor example, if you distribute copies of such a program, whether gratis or for\na fee, you must give the recipients all the rights that you have.  You must\nmake sure that they, too, receive or can get the source code.  And you must\nshow them these terms so they know their rights.\n\nWe protect your rights with two steps: (1) copyright the software, and (2)\noffer you this license which gives you legal permission to copy, distribute\nand/or modify the software.\n\nAlso, for each author's protection and ours, we want to make certain that\neveryone understands that there is no warranty for this free software.  If the\nsoftware is modified by someone else and passed on, we want its recipients to\nknow that what they have is not the original, so that any problems introduced\nby others will not reflect on the original authors' reputations.\n\nFinally, any free program is threatened constantly by software patents.  We\nwish to avoid the danger that redistributors of a free program will\nindividually obtain patent licenses, in effect making the program proprietary.\nTo prevent this, we have made it clear that any patent must be licensed for\neveryone's free use or not licensed at all.\n\nThe precise terms and conditions for copying, distribution and modification\nfollow.\n\nTERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n0. This License applies to any program or other work which contains a notice\nplaced by the copyright holder saying it may be distributed under the terms of\nthis General Public License.  The \"Program\", below, refers to any such program\nor work, and a \"work based on the Program\" means either the Program or any\nderivative work under copyright law: that is to say, a work containing the\nProgram or a portion of it, either verbatim or with modifications and/or\ntranslated into another language.  (Hereinafter, translation is included\nwithout limitation in the term \"modification\".) Each licensee is addressed as\n\"you\".\n\nActivities other than copying, distribution and modification are not covered by\nthis License; they are outside its scope.  The act of running the Program is\nnot restricted, and the output from the Program is covered only if its contents\nconstitute a work based on the Program (independent of having been made by\nrunning the Program).  Whether that is true depends on what the Program does.\n\n1. You may copy and distribute verbatim copies of the Program's source code as\nyou receive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice and\ndisclaimer of warranty; keep intact all the notices that refer to this License\nand to the absence of any warranty; and give any other recipients of the\nProgram a copy of this License along with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and you may\nat your option offer warranty protection in exchange for a fee.\n\n2. You may modify your copy or copies of the Program or any portion of it, thus\nforming a work based on the Program, and copy and distribute such modifications\nor work under the terms of Section 1 above, provided that you also meet all of\nthese conditions:\n\n    a) You must cause the modified files to carry prominent notices stating\n    that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in whole or\n    in part contains or is derived from the Program or any part thereof, to be\n    licensed as a whole at no charge to all third parties under the terms of\n    this License.\n\n    c) If the modified program normally reads commands interactively when run,\n    you must cause it, when started running for such interactive use in the\n    most ordinary way, to print or display an announcement including an\n    appropriate copyright notice and a notice that there is no warranty (or\n    else, saying that you provide a warranty) and that users may redistribute\n    the program under these conditions, and telling the user how to view a copy\n    of this License.  (Exception: if the Program itself is interactive but does\n    not normally print such an announcement, your work based on the Program is\n    not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If identifiable\nsections of that work are not derived from the Program, and can be reasonably\nconsidered independent and separate works in themselves, then this License, and\nits terms, do not apply to those sections when you distribute them as separate\nworks.  But when you distribute the same sections as part of a whole which is a\nwork based on the Program, the distribution of the whole must be on the terms\nof this License, whose permissions for other licensees extend to the entire\nwhole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest your\nrights to work written entirely by you; rather, the intent is to exercise the\nright to control the distribution of derivative or collective works based on\nthe Program.\n\nIn addition, mere aggregation of another work not based on the Program with the\nProgram (or with a work based on the Program) on a volume of a storage or\ndistribution medium does not bring the other work under the scope of this\nLicense.\n\n3. You may copy and distribute the Program (or a work based on it, under\nSection 2) in object code or executable form under the terms of Sections 1 and\n2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable source\n    code, which must be distributed under the terms of Sections 1 and 2 above\n    on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three years, to\n    give any third party, for a charge no more than your cost of physically\n    performing source distribution, a complete machine-readable copy of the\n    corresponding source code, to be distributed under the terms of Sections 1\n    and 2 above on a medium customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer to\n    distribute corresponding source code.  (This alternative is allowed only\n    for noncommercial distribution and only if you received the program in\n    object code or executable form with such an offer, in accord with\n    Subsection b above.)\n\nThe source code for a work means the preferred form of the work for making\nmodifications to it.  For an executable work, complete source code means all\nthe source code for all modules it contains, plus any associated interface\ndefinition files, plus the scripts used to control compilation and installation\nof the executable.  However, as a special exception, the source code\ndistributed need not include anything that is normally distributed (in either\nsource or binary form) with the major components (compiler, kernel, and so on)\nof the operating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the source\ncode from the same place counts as distribution of the source code, even though\nthird parties are not compelled to copy the source along with the object code.\n\n4. You may not copy, modify, sublicense, or distribute the Program except as\nexpressly provided under this License.  Any attempt otherwise to copy, modify,\nsublicense or distribute the Program is void, and will automatically terminate\nyour rights under this License.  However, parties who have received copies, or\nrights, from you under this License will not have their licenses terminated so\nlong as such parties remain in full compliance.\n\n5. You are not required to accept this License, since you have not signed it.\nHowever, nothing else grants you permission to modify or distribute the Program\nor its derivative works.  These actions are prohibited by law if you do not\naccept this License.  Therefore, by modifying or distributing the Program (or\nany work based on the Program), you indicate your acceptance of this License to\ndo so, and all its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n6. Each time you redistribute the Program (or any work based on the Program),\nthe recipient automatically receives a license from the original licensor to\ncopy, distribute or modify the Program subject to these terms and conditions.\nYou may not impose any further restrictions on the recipients' exercise of the\nrights granted herein.  You are not responsible for enforcing compliance by\nthird parties to this License.\n\n7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues), conditions\nare imposed on you (whether by court order, agreement or otherwise) that\ncontradict the conditions of this License, they do not excuse you from the\nconditions of this License.  If you cannot distribute so as to satisfy\nsimultaneously your obligations under this License and any other pertinent\nobligations, then as a consequence you may not distribute the Program at all.\nFor example, if a patent license would not permit royalty-free redistribution\nof the Program by all those who receive copies directly or indirectly through\nyou, then the only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply and\nthe section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any patents or\nother property right claims or to contest validity of any such claims; this\nsection has the sole purpose of protecting the integrity of the free software\ndistribution system, which is implemented by public license practices.  Many\npeople have made generous contributions to the wide range of software\ndistributed through that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing to\ndistribute software through any other system and a licensee cannot impose that\nchoice.\n\nThis section is intended to make thoroughly clear what is believed to be a\nconsequence of the rest of this License.\n\n8. If the distribution and/or use of the Program is restricted in certain\ncountries either by patents or by copyrighted interfaces, the original\ncopyright holder who places the Program under this License may add an explicit\ngeographical distribution limitation excluding those countries, so that\ndistribution is permitted only in or among countries not thus excluded.  In\nsuch case, this License incorporates the limitation as if written in the body\nof this License.\n\n9. The Free Software Foundation may publish revised and/or new versions of the\nGeneral Public License from time to time.  Such new versions will be similar in\nspirit to the present version, but may differ in detail to address new problems\nor concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any later\nversion\", you have the option of following the terms and conditions either of\nthat version or of any later version published by the Free Software Foundation.\nIf the Program does not specify a version number of this License, you may\nchoose any version ever published by the Free Software Foundation.\n\n10. If you wish to incorporate parts of the Program into other free programs\nwhose distribution conditions are different, write to the author to ask for\npermission.  For software which is copyrighted by the Free Software Foundation,\nwrite to the Free Software Foundation; we sometimes make exceptions for this.\nOur decision will be guided by the two goals of preserving the free status of\nall derivatives of our free software and of promoting the sharing and reuse of\nsoftware generally.\n\nNO WARRANTY\n\n11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR\nTHE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN OTHERWISE\nSTATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE\nPROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,\nINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND\nPERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE,\nYOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL\nANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE\nPROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR\nINABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA\nBEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER\nOR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n\nEND OF TERMS AND CONDITIONS\n\nHow to Apply These Terms to Your New Programs\n\nIf you develop a new program, and you want it to be of the greatest possible\nuse to the public, the best way to achieve this is to make it free software\nwhich everyone can redistribute and change under these terms.\n\nTo do so, attach the following notices to the program.  It is safest to attach\nthem to the start of each source file to most effectively convey the exclusion\nof warranty; and each file should have at least the \"copyright\" line and a\npointer to where the full notice is found.\n\n    One line to give the program's name and a brief idea of what it does.\n\n    Copyright (C) <year> <name of author>\n\n    This program is free software; you can redistribute it and/or modify it\n    under the terms of the GNU General Public License as published by the Free\n    Software Foundation; either version 2 of the License, or (at your option)\n    any later version.\n\n    This program is distributed in the hope that it will be useful, but WITHOUT\n    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n    more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc., 59\n    Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this when it\nstarts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author Gnomovision comes\n    with ABSOLUTELY NO WARRANTY; for details type 'show w'.  This is free\n    software, and you are welcome to redistribute it under certain conditions;\n    type 'show c' for details.\n\nThe hypothetical commands 'show w' and 'show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may be\ncalled something other than 'show w' and 'show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.  Here\nis a sample; alter the names:\n\n    Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n    'Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n    signature of Ty Coon, 1 April 1989\n\n    Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General Public\nLicense instead of this License.\n\n\n\"CLASSPATH\" EXCEPTION TO THE GPL\n\nCertain source files distributed by Oracle America and/or its affiliates are\nsubject to the following clarification and special exception to the GPL, but\nonly where Oracle has expressly included in the particular source file's header\nthe words \"Oracle designates this particular file as subject to the \"Classpath\"\nexception as provided by Oracle in the LICENSE file that accompanied this code.\"\n\n    Linking this library statically or dynamically with other modules is making\n    a combined work based on this library.  Thus, the terms and conditions of\n    the GNU General Public License cover the whole combination.\n\n    As a special exception, the copyright holders of this library give you\n    permission to link this library with independent modules to produce an\n    executable, regardless of the license terms of these independent modules,\n    and to copy and distribute the resulting executable under terms of your\n    choice, provided that you also meet, for each linked independent module,\n    the terms and conditions of the license of that module.  An independent\n    module is a module which is not derived from or based on this library.  If\n    you modify this library, you may extend this exception to your version of\n    the library, but you are not obligated to do so.  If you do not wish to do\n    so, delete this exception statement from your version.\n\n\n[All 3rd party libraries licenses are listed in LICENSE-3RD-PARTY.txt file]"
  },
  {
    "path": "btrace-dist/src/main/resources/LICENSE-3RD-PARTY.txt",
    "content": "[lib/btrace-asm-5.0.4.jar](http://asm.ow2.org/)\nCopyright (c) 2000-2011 INRIA, France Telecom\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holders nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\nTHE POSSIBILITY OF SUCH DAMAGE.\n\n\n[lib/btrace-jctools-1.2.jar](https://github.com/JCTools/JCTools)\n[lib/btrace-hppcrt-0.7.4.jar](https://github.com/vsonnier/hppcrt)\nApache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "btrace-dist/src/main/resources/THIRDPARTYLICENSEREADME.txt",
    "content": "DO NOT TRANSLATE OR LOCALIZE.\n\n%% The following software is used by BTrace: ASM 5.0; Use of any of this software is governed by the terms of the license below: \n\n/***\n * ASM: a very small and fast Java bytecode manipulation framework\n * Copyright (c) 2000-2011 INRIA, France Telecom\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. Neither the name of the copyright holders nor the names of its\n *    contributors may be used to endorse or promote products derived from\n *    this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n */\n"
  },
  {
    "path": "btrace-dist/src/main/resources/bin/btrace",
    "content": "#! /bin/sh\n\nif [ -z \"$BTRACE_HOME\" -o ! -d \"$BTRACE_HOME\" ]; then\n  # resolve links - $0 could be a link to btrace's home\n  PRG=\"$0\"\n  progname=$(basename \"$0\")\n  PRG=$(readlink \"$PRG\")\n\n  if [ -z \"$PRG\" ]; then\n    PRG=$0\n  fi\n  BTRACE_HOME=$(dirname \"$PRG\")/..\n  BTRACE_HOME=$(cd \"$BTRACE_HOME\" && pwd)\nfi\n\nJAVA_ARGS=\"-XX:+IgnoreUnrecognizedVMOptions\"\nif [ -d \"${JAVA_HOME}/jmods\" ]; then\n  JAVA_ARGS=\"$JAVA_ARGS -XX:+AllowRedefinitionToAddDeleteMethods\"\n  JAVA_ARGS=\"$JAVA_ARGS --add-exports jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"\nfi\n\nCLIENT_JAR=\"${BTRACE_HOME}/libs/btrace.jar\"\nif [ -f \"${CLIENT_JAR}\" ]; then\n  if [ -d \"${JAVA_HOME}\" ]; then\n    TOOLS_JAR=\"$JAVA_HOME/lib/tools.jar\"\n\n    if [ ! -f \"$TOOLS_JAR\" ]; then\n      # probably running on JRE - try to localize JDK\n      TOOLS_JAR=\"$JAVA_HOME/../lib/tools.jar\"\n    fi\n\n    if [ ! -f \"${TOOLS_JAR}\" ] && [ ! -d \"${JAVA_HOME}/jmods\" ]; then\n      # old Java versions on MacOS don't have tools.jar at all\n      case \"$(uname)\" in\n      Darwin*)\n        # In older JDK versions for Mac OS X, tools.jar is classes.jar\n        # and is kept in a different location. Check if we can locate\n        # classes.jar based on ${JAVA_VERSION}\n        TOOLS_JAR=\"/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Classes/classes.jar\"\n\n        # if we can't find, try relative path from ${JAVA_HOME}. Usually,\n        # /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home\n        # is JAVA_HOME. (or whatever version beyond 1.6.0!)\n        if [ ! -f \"${TOOLS_JAR}\" ]; then\n          TOOLS_JAR=\"${JAVA_HOME}/../Classes/classes.jar\"\n        fi\n\n        # If we still can't find, tell the user to set JAVA_VERSION.\n        # This way, we can avoid zip file errors from the agent side\n        # and \"connection refused\" message from client.\n        if [ ! -f \"${TOOLS_JAR}\" ]; then\n          echo \"Please set JAVA_VERSION to the target java version\"\n          exit 1\n        fi\n        ;;\n      esac\n    fi\n    if [ ! -f \"${TOOLS_JAR}\" ] && [ ! -d \"${JAVA_HOME}/jmods\" ]; then\n      # in non-jigsaw world TOOLS_JAR must point to a valid file\n      echo \"Unable to locate tools.jar. Please, make sure JAVA_HOME points to a valid JDK installation\"\n      exit 1\n    fi\n    ${JAVA_HOME}/bin/java ${JAVA_ARGS} -cp ${CLIENT_JAR}:${TOOLS_JAR}:/usr/share/lib/java/dtrace.jar org.openjdk.btrace.boot.Loader $*\n  else\n    echo \"Please set a valid JAVA_HOME before running this script\"\n    exit 1\n  fi\nelse\n  echo \"Please set BTRACE_HOME before running this script\"\n  exit 1\nfi\n"
  },
  {
    "path": "btrace-dist/src/main/resources/bin/btrace.bat",
    "content": "@echo off\n\nrem %~dp0 is expanded pathname of the current script under NT\nset DEFAULT_BTRACE_HOME=%~dp0..\n\nif \"%BTRACE_HOME%\"==\"\" set BTRACE_HOME=%DEFAULT_BTRACE_HOME%\nset DEFAULT_BTRACE_HOME=\n\nset CLIENT_JAR=%BTRACE_HOME%\\libs\\btrace.jar\nif not exist \"%CLIENT_JAR%\" goto noBTraceHome\n\nif \"%JAVA_HOME%\" == \"\" goto noJavaHome\n  set JAVA_ARGS=\"-XX:+IgnoreUnrecognizedVMOptions\"\n  if exist \"%JAVA_HOME%/jmods/\" (\n    set JAVA_ARGS=\"%JAVA_ARGS% -XX:+AllowRedefinitionToAddDeleteMethods\"\n    set JAVA_ARGS=\"%JAVA_ARGS% --add-exports jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"\n  )\n  \"%JAVA_HOME%/bin/java\" \"%JAVA_ARGS%\" -cp \"%CLIENT_JAR%;%JAVA_HOME%/lib/tools.jar\" org.openjdk.btrace.boot.Loader %*\n  goto end\n:noJavaHome\n  echo Please set JAVA_HOME before running this script\n  goto end\n:noBTraceHome\n  echo Please set BTRACE_HOME before running this script\n:end\n"
  },
  {
    "path": "btrace-dist/src/main/resources/bin/btracec",
    "content": "#! /bin/sh\n\nif [ -z \"$BTRACE_HOME\" -o ! -d \"$BTRACE_HOME\" ]; then\n  # resolve links - $0 could be a link to btrace's home\n  PRG=\"$0\"\n  progname=$(basename \"$0\")\n  PRG=$(readlink \"$PRG\")\n\n  if [ -z \"$PRG\" ]; then\n    PRG=$0\n  fi\n  BTRACE_HOME=$(dirname \"$PRG\")/..\n  BTRACE_HOME=$(cd \"$BTRACE_HOME\" && pwd)\nfi\nJAVA_ARGS=\"-XX:+IgnoreUnrecognizedVMOptions\"\nif [ -d \"${JAVA_HOME}/jmods\" ]; then\n  JAVA_ARGS=\"$JAVA_ARGS --add-exports jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"\nfi\nCLIENT_JAR=\"${BTRACE_HOME}/libs/btrace.jar\"\nif [ -f \"${CLIENT_JAR}\" ]; then\n  if [ -d \"${JAVA_HOME}\" ]; then\n    if [ \"$1\" = \"--version\" ]; then\n      ${JAVA_HOME}/bin/java ${JAVA_ARGS} -cp ${CLIENT_JAR} org.openjdk.btrace.boot.Loader --version\n      exit 0\n    fi\n    TOOLS_JAR=\"$JAVA_HOME/lib/tools.jar\"\n\n    if [ ! -f \"$TOOLS_JAR\" ]; then\n      # probably running on JRE - try to localize JDK\n      TOOLS_JAR=\"$JAVA_HOME/../lib/tools.jar\"\n    fi\n\n    if [ ! -f \"${TOOLS_JAR}\" ] && [ ! -d \"${JAVA_HOME}/jmods\" ]; then\n      # old Java versions on MacOS don't have tools.jar at all\n      case \"$(uname)\" in\n      Darwin*)\n        if [ -f /System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Classes/classes.jar ]; then\n          TOOLS_JAR=\"/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Classes/classes.jar\"\n        else\n          TOOLS_JAR=\"${JAVA_HOME}/lib/tools.jar\"\n        fi\n        ;;\n      *)\n        TOOLS_JAR=\"${JAVA_HOME}/lib/tools.jar\"\n        ;;\n      esac\n    fi\n    if [ ! -f \"${TOOLS_JAR}\" ] && [ ! -d \"${JAVA_HOME}/jmods\" ]; then\n      # in non-jigsaw world TOOLS_JAR must point to a valid file\n      echo \"Unable to locate tools.jar. Please, make sure JAVA_HOME points to a valid JDK installation\"\n      exit 1\n    fi\n\n    ${JAVA_HOME}/bin/java ${JAVA_ARGS} -cp ${CLIENT_JAR}:${TOOLS_JAR} org.openjdk.btrace.compiler.Compiler $*\n  else\n    echo \"Please set a valid JAVA_HOME before running this script\"\n    exit 1\n  fi\nelse\n  echo \"Please set BTRACE_HOME before running this script\"\n  exit 1\nfi\n"
  },
  {
    "path": "btrace-dist/src/main/resources/bin/btracec.bat",
    "content": "@echo off\n\nrem %~dp0 is expanded pathname of the current script under NT\nset DEFAULT_BTRACE_HOME=%~dp0..\n\nif \"%BTRACE_HOME%\"==\"\" set BTRACE_HOME=%DEFAULT_BTRACE_HOME%\nset DEFAULT_BTRACE_HOME=\n\nset CLIENT_JAR=%BTRACE_HOME%\\libs\\btrace.jar\nif not exist \"%CLIENT_JAR%\" goto noBTraceHome\n\nif \"%JAVA_HOME%\" == \"\" goto noJavaHome\n  if exist \"%JAVA_HOME%/jmods/\" (\n    set JAVA_ARGS=\"%JAVA_ARGS% -XX:+AllowRedefinitionToAddDeleteMethods\"\n    set JAVA_ARGS=\"%JAVA_ARGS% --add-exports jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"\n  )\n  if \"%1\" == \"--version\" (\n    %JAVA_HOME%\\bin\\java \"%JAVA_ARGS%\" -cp %CLIENT_JAR% org.openjdk.btrace.boot.Loader --version\n    goto end\n  )\n  \"%JAVA_HOME%/bin/java\" \"%JAVA_ARGS%\" -cp \"%CLIENT_JAR%;%JAVA_HOME%/lib/tools.jar\" org.openjdk.btrace.boot.Loader %*\n  goto end\n:noJavaHome\n  echo Please set JAVA_HOME before running this script\n  goto end\n:noBTraceHome\n  echo Please set BTRACE_HOME before running this script\n:end\n"
  },
  {
    "path": "btrace-dist/src/main/resources/bin/btracep",
    "content": "#! /bin/sh\n\nif [ -z \"$BTRACE_HOME\" -o ! -d \"$BTRACE_HOME\" ]; then\n  # resolve links - $0 could be a link to btrace's home\n  PRG=\"$0\"\n  progname=$(basename \"$0\")\n  PRG=$(readlink \"$PRG\")\n\n  if [ -z \"$PRG\" ]; then\n    PRG=$0\n  fi\n  BTRACE_HOME=$(dirname \"$PRG\")/..\n  BTRACE_HOME=$(cd \"$BTRACE_HOME\" && pwd)\nfi\n\nJAVA_ARGS=\"-XX:+IgnoreUnrecognizedVMOptions\"\nif [ -d \"${JAVA_HOME}/jmods\" ]; then\n  JAVA_ARGS=\"$JAVA_ARGS -XX:+AllowRedefinitionToAddDeleteMethods\"\n  JAVA_ARGS=\"$JAVA_ARGS --add-exports jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"\nfi\n\nCLIENT_JAR=\"${BTRACE_HOME}/libs/btrace.jar\"\nif [ -f \"${CLIENT_JAR}\" ]; then\n  if [ -d \"${JAVA_HOME}\" ]; then\n    if [ \"$1\" = \"--version\" ]; then\n      ${JAVA_HOME}/bin/java ${JAVA_ARGS} -cp ${CLIENT_JAR} org.openjdk.btrace.boot.Loader --version\n      exit 0\n    fi\n    TOOLS_JAR=\"$JAVA_HOME/lib/tools.jar\"\n\n    if [ ! -f \"$TOOLS_JAR\" ]; then\n      # probably running on JRE - try to localize JDK\n      TOOLS_JAR=\"$JAVA_HOME/../lib/tools.jar\"\n    fi\n\n    if [ ! -f \"${TOOLS_JAR}\" ] && [ ! -d \"${JAVA_HOME}/jmods\" ]; then\n      # old Java versions on MacOS don't have tools.jar at all\n      case \"$(uname)\" in\n      Darwin*)\n        if [ -f /System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Classes/classes.jar ]; then\n          TOOLS_JAR=\"/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Classes/classes.jar\"\n        else\n          TOOLS_JAR=\"${JAVA_HOME}/lib/tools.jar\"\n        fi\n        ;;\n      *)\n        TOOLS_JAR=\"${JAVA_HOME}/lib/tools.jar\"\n        ;;\n      esac\n    fi\n    if [ ! -f \"${TOOLS_JAR}\" ] && [ ! -d \"${JAVA_HOME}/jmods\" ]; then\n      # in non-jigsaw world TOOLS_JAR must point to a valid file\n      echo \"Unable to locate tools.jar. Please, make sure JAVA_HOME points to a valid JDK installation\"\n      exit 1\n    fi\n\n    ${JAVA_HOME}/bin/java ${JAVA_ARGS} -cp ${CLIENT_JAR}:${TOOLS_JAR} org.openjdk.btrace.client.ProbePrinter $*\n  else\n    echo \"Please set a valid JAVA_HOME before running this script\"\n    exit 1\n  fi\nelse\n  echo \"Please set BTRACE_HOME before running this script\"\n  exit 1\nfi\n"
  },
  {
    "path": "btrace-dist/src/main/resources/bin/btracep.bat",
    "content": "@echo off\n\nrem %~dp0 is expanded pathname of the current script under NT\nset DEFAULT_BTRACE_HOME=%~dp0..\n\nif \"%BTRACE_HOME%\"==\"\" set BTRACE_HOME=%DEFAULT_BTRACE_HOME%\nset DEFAULT_BTRACE_HOME=\n\nset CLIENT_JAR=%BTRACE_HOME%\\libs\\btrace.jar\nif not exist \"%CLIENT_JAR%\" goto noBTraceHome\n\nif \"%JAVA_HOME%\" == \"\" goto noJavaHome\n  if exist \"%JAVA_HOME%/jmods/\" (\n    set JAVA_ARGS=\"%JAVA_ARGS% -XX:+AllowRedefinitionToAddDeleteMethods\"\n    set JAVA_ARGS=\"%JAVA_ARGS% --add-exports jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"\n  )\n  if \"%1\" == \"--version\" (\n    %JAVA_HOME%\\bin\\java \"%JAVA_ARGS%\" -cp %CLIENT_JAR% org.openjdk.btrace.boot.Loader --version\n    goto end\n  )\n  \"%JAVA_HOME%/bin/java\" \"%JAVA_ARGS%\" -cp \"%CLIENT_JAR%;%JAVA_HOME%/lib/tools.jar\" org.openjdk.btrace.client.ProbePrinter $*\n  goto end\n:noJavaHome\n  echo Please set JAVA_HOME before running this script\n  goto end\n:noBTraceHome\n  echo Please set BTRACE_HOME before running this script\n:end\n"
  },
  {
    "path": "btrace-dist/src/main/resources/bin/btracer",
    "content": "#! /bin/sh\n\nif [ -z \"$BTRACE_HOME\" ] || [ ! -d \"$BTRACE_HOME\" ]; then\n  # resolve links - $0 could be a link to btrace's home\n  PRG=\"$0\"\n  progname=$(basename \"$0\")\n  PRG=$(readlink \"$PRG\")\n\n  if [ -z \"$PRG\" ]; then\n    PRG=$0\n  fi\n  BTRACE_HOME=$(dirname \"$PRG\")/..\n  BTRACE_HOME=$(cd \"$BTRACE_HOME\" && pwd)\nfi\n\nusage() {\n  echo \"btracer <options> <compiled script> <java args>\"\n  echo \"Options:\"\n  echo \"    --version\\t\\t\\tShow BTrace version\"\n  echo \"    -v\\t\\t\\t\\tRun in verbose mode\"\n  echo \"    -u\\t\\t\\t\\tRun in unsafe mode\"\n  echo \"    -p <port>\\t\\t\\tBTrace agent server port\"\n  echo \"    -statsd <host>[:<port>]\\tUse this StatsD server\"\n  echo \"    -o <file>\\t\\t\\tThe path to a file the btrace agent will store its output\"\n  echo \"    -d <path>\\t\\t\\tDump modified classes to the provided location\"\n  echo \"    -pd <path>\\t\\t\\tSearch for the probe XML descriptors here\"\n  echo \"    --noserver\\t\\t\\tDon't start the socket server\"\n  echo \"    --stdout\\t\\t\\tRedirect the btrace output to stdout instead of writing it to an arbitrary file\"\n  echo \"    -bcp <cp>\\t\\t\\tAppend to bootstrap class path\"\n  echo \"    -scp <cp>\\t\\t\\tAppend to system class path\"\n  echo \"    -h\\t\\t\\t\\tThis message\"\n  exit 0\n}\n\nif [ $# -eq 0 ]; then\n  usage\nfi\n\nJAVA_ARGS=\"-XX:+IgnoreUnrecognizedVMOptions\"\nif [ -d \"${JAVA_HOME}/jmods\" ]; then\n  JAVA_ARGS=\"$JAVA_ARGS -XX:+AllowRedefinitionToAddDeleteMethods\"\n  JAVA_ARGS=\"$JAVA_ARGS --add-exports jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"\nfi\nCLIENT_JAR=\"${BTRACE_HOME}/libs/btrace.jar\"\n\nOPTIONS=\n\nif [ -d \"${JAVA_HOME}\" ]; then\n  while [ true ]; do\n    case $1 in\n    -v)\n      OPTIONS=\"debug=true,$OPTIONS\"\n      ;;\n    -u)\n      OPTIONS=\"unsafe=true,$OPTIONS\"\n      ;;\n    -p)\n      OPTIONS=\"port=$2,$OPTIONS\"\n      shift\n      ;;\n    -d)\n      OPTIONS=\"dumpClasses=true,dumpDir=$2,$OPTIONS\"\n      shift\n      ;;\n    -o)\n      OPTIONS=\"scriptOutputFile=$2,$OPTIONS\"\n      shift\n      ;;\n    -pd)\n      OPTIONS=\"probeDescPath=$2,$OPTIONS\"\n      shift\n      ;;\n    -bcp)\n      OPTIONS=\"bootClassPath=$2,$OPTIONS\"\n      shift\n      ;;\n    -scp)\n      OPTIONS=\"systemClassPath=$2,$OPTIONS\"\n      shift\n      ;;\n    -statsd)\n      OPTIONS=\"statsd=$2,$OPTIONS\"\n      ;;\n    --noserver)\n      OPTIONS=\"noServer=true,$OPTIONS\"\n      ;;\n    --stdout)\n      OPTIONS=\"stdout=true,$OPTIONS\"\n      ;;\n    --version)\n      if [ -z \"${CLIENT_JAR}\" ]; then\n        echo \"Please set BTRACE_HOME before running this script\"\n        exit 1\n      fi\n      $JAVA_HOME/bin/java ${JAVA_ARGS} -cp ${CLIENT_JAR} org.openjdk.btrace.boot.Loader --version\n      exit 0\n      ;;\n    -h)\n      usage\n      ;;\n    *)\n      break\n      ;;\n    esac\n    shift\n  done\n\n  if [ -f \"${BTRACE_HOME}/libs/btrace-agent.jar\" ]; then\n    ${JAVA_HOME}/bin/java -Xshare:off ${JAVA_ARGS} -javaagent:${BTRACE_HOME}/libs/btrace-agent.jar=$OPTIONS,script=\"$@\"\n  else\n    echo \"Please set BTRACE_HOME before running this script\"\n  fi\nelse\n  echo \"Please set a valid JAVA_HOME before running this script\"\n  exit 1\nfi\n"
  },
  {
    "path": "btrace-dist/src/main/resources/bin/btracer.bat",
    "content": "@echo off\n\nrem %~dp0 is expanded pathname of the current script under NT\nset DEFAULT_BTRACE_HOME=%~dp0..\n\nif \"%BTRACE_HOME%\"==\"\" set BTRACE_HOME=%DEFAULT_BTRACE_HOME%\nset DEFAULT_BTRACE_HOME=\n\nif not exist \"%BTRACE_HOME%\\libs \\btrace-agent.jar\" goto noBTraceHome\n\nset OPTIONS=\n\nif \"%1\"==\"\" (\n  call:usage\n  goto end\n)\nif \"%JAVA_HOME%\" == \"\" goto noJavaHome\n\nif exist \"%JAVA_HOME%/jmods/\" (\n  set JAVA_ARGS=\"%JAVA_ARGS% -XX:+AllowRedefinitionToAddDeleteMethods\"\n  set JAVA_ARGS=\"%JAVA_ARGS% --add-exports jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"\n)\n\nif \"%1\" == \"--version\" (\n  set CLIENT_JAR=%BTRACE_HOME%\\libs\\btrace.jar\n  if not exist \"%CLIENT_JAR%\" goto noBTraceHome\n  %JAVA_HOME%\\bin\\java \"%JAVA_ARGS%\" -cp %CLIENT_JAR% org.openjdk.btrace.boot.Loader --version\n  goto end\n)\n\nset inloop=1\n:loop\n  IF \"%1\"==\"-v\" (\n    set OPTIONS=\"debug=true,%OPTIONS\"\n    goto next\n  )\n  IF \"%1\"==\"-u\" (\n    set OPTIONS=\"unsafe=true,%OPTIONS\"\n    goto next\n  )\n  if \"%1\"==\"-p\" (\n    set OPTIONS=\"port=%2,%OPTIONS\"\n    shift\n    goto next\n  )\n  if \"%1\"==\"-d\" (\n    set OPTIONS=\"dumpClasses=true,dumpDir=%2,%OPTIONS\"\n     shift\n    goto next\n  )\n  if \"%1\"==\"-o\" (\n    set OPTIONS=\"scriptOutputFile=%2,%OPTIONS\"\n    shift\n    goto next\n  )\n  if \"%1\"==\"-pd\" (\n    set OPTIONS=\"probeDescPath=%2,%OPTIONS\"\n    shift\n    goto next\n  )\n  if \"%1\"==\"-bcp\" (\n    OPTIONS=\"bootClassPath=%2,%OPTIONS\"\n    shift\n    goto next\n  )\n  if \"%1\"==\"-scp\" (\n    set OPTIONS=\"systemClassPath=%2,%OPTIONS\"\n    shift\n    goto next\n  )\n  if \"%1\"==\"--noserver\" (\n    set OPTIONS=\"noServer=true,%OPTIONS\"\n    goto next\n  )\n  if \"%1\"==\"--stdout\" (\n    set OPTIONS=\"stdout=true,%OPTIONS\"\n    goto next\n  )\n  if \"%1\"==\"-statsd\" (\n    set OPTIONS=\"statsd=%2,%OPTIONS\"\n    goto next\n  )\n  call :usage\n  goto end\n\n  set inloop=0\n\n  :next\n  if %inloop==1 (\n    shift\n    goto loop\n  )\n\n%JAVA_HOME%\\bin\\java -Xshare:off \"%JAVA_ARGS%\" \"-javaagent:%BTRACE_HOME%/libs/btrace-agent.jar=%OPTIONS,script=%~1\" %2 %3 %4 %5 %6 %7 %8 %9\ngoto end\n\n:noJavaHome\n  echo Please set JAVA_HOME before running this script\n  goto end\n:noBTraceHome\n  echo Please set BTRACE_HOME before running this script\n  goto end\n\n:usage\n  echo btracer ^<options^> ^<compiled script^> ^<java args^>\n  echo Options:\n  echo     -v\t\t          Run in verbose mode\n  echo     -u\t\t          Run in unsafe mode\n  echo     -p ^<port^>\t            BTrace agent server port\n  echo     -statsd ^<host[:port]^>  Use this StatsD server\n  echo     -o ^<file^>\t            The path to a file the btrace agent will store its output\n  echo     -d ^<path^>\t            Dump modified classes to the provided location\n  echo     -pd ^<path^>\t            Search for the probe XML descriptors here\n  echo     --noserver\t          Don't start the socket server\n  echo     --stdout\t          Redirect the btrace output to stdout instead of writing it to an arbitrary file\n  echo     -bcp ^<cp^>\t            Append to bootstrap class path\n  echo     -scp ^<cp^>\t            Append to system class path\n  echo     -h\t\t          This message\n\n:end\n"
  },
  {
    "path": "btrace-dist/src/main/resources/bin/btracex",
    "content": "#! /bin/sh\n\nif [ -z \"$BTRACE_HOME\" -o ! -d \"$BTRACE_HOME\" ]; then\n  PRG=\"$0\"\n  progname=$(basename \"$0\")\n  PRG=$(readlink \"$PRG\")\n  if [ -z \"$PRG\" ]; then PRG=$0; fi\n  BTRACE_HOME=$(dirname \"$PRG\")/..\n  BTRACE_HOME=$(cd \"$BTRACE_HOME\" && pwd)\nfi\n\nJAVA_ARGS=\"-XX:+IgnoreUnrecognizedVMOptions\"\n\nCLIENT_JAR=\"${BTRACE_HOME}/libs/btrace.jar\"\nif [ -f \"${CLIENT_JAR}\" ]; then\n  if [ -d \"${JAVA_HOME}\" ]; then\n    CP=\"${CLIENT_JAR}\"\n    ${JAVA_HOME}/bin/java ${JAVA_ARGS} -cp ${CP} org.openjdk.btrace.extcli.Main \"$@\"\n  else\n    echo \"Please set a valid JAVA_HOME before running this script\"\n    exit 1\n  fi\nelse\n  echo \"Please set BTRACE_HOME before running this script\"\n  exit 1\nfi\n"
  },
  {
    "path": "btrace-dist/src/main/resources/bin/btracex.bat",
    "content": "@echo off\nsetlocal enableextensions\n\nif not defined BTRACE_HOME (\n  set SCRIPT=%~f0\n  for %%i in (\"%SCRIPT%\") do set BTRACE_HOME=%%~dpi..\\\n)\n\nif not defined JAVA_HOME (\n  echo Please set JAVA_HOME before running this script\n  exit /b 1\n)\n\nset JAR=%BTRACE_HOME%\\libs\\btrace.jar\nif not exist \"%JAR%\" (\n  echo Could not find %JAR%\n  exit /b 1\n)\n\nset CP=\"%JAR%\"\n\"%JAVA_HOME%\\bin\\java\" -cp %CP% org.openjdk.btrace.extcli.Main %*\n\nendlocal\n"
  },
  {
    "path": "btrace-dist/src/main/resources/conf/extensions.conf",
    "content": "# BTrace Extension Configuration\n#\n# This file controls which extensions are loaded and how they behave.\n# Configuration is read from (in priority order):\n#   1. Command-line: -Dbtrace.extensions.config=/path/to/config\n#   2. User config: ~/.btrace/extensions.conf\n#   3. System config: $BTRACE_HOME/conf/extensions.conf\n#\n# Only the first file found is used (no merging).\n\n# ============================================================================\n# Extension Control\n# ============================================================================\n\n# extensions.enabled\n# Whitelist of extension IDs to load (comma-separated).\n# If empty or not set, all discovered extensions are enabled.\n# If set, ONLY listed extensions will be loaded.\n#\n# Examples:\n#   extensions.enabled=btrace-metrics\n#   extensions.enabled=btrace-metrics,my-custom-extension\n#\nextensions.enabled=\n\n# extensions.disabled\n# Blacklist of extension IDs to prevent from loading (comma-separated).\n# Takes precedence over extensions.enabled.\n# Use this to selectively disable specific extensions.\n#\n# Examples:\n#   extensions.disabled=btrace-old-version\n#   extensions.disabled=extension-a,extension-b\n#\nextensions.disabled=\n\n# extensions.autoload\n# Control when extensions are loaded:\n#   true  = Lazy loading (extensions loaded on demand when scripts use them)\n#   false = Eager loading (all enabled extensions loaded at agent startup)\n#\n# Default: true\n# Lazy loading reduces startup time and memory usage.\n# Eager loading ensures all extensions are available immediately.\n#\nextensions.autoload=true\n\n# ============================================================================\n# Extension-Specific Settings\n# ============================================================================\n\n# Extension-specific properties use the format:\n#   <extension-id>.<setting-name>=<value>\n#\n# These settings are passed to the extension when it's loaded.\n# Check extension documentation for supported settings.\n\n# Example: BTrace Metrics Extension Settings\n# btrace-metrics.histogram.default-precision=3\n# btrace-metrics.histogram.max-value=3600000000\n# btrace-metrics.stats.window-size=1000\n\n# Example: Custom Extension Settings\n# my-extension.feature.enabled=true\n# my-extension.endpoint=http://localhost:8080\n# my-extension.timeout=5000\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AWTEventTracer.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport java.awt.*;\nimport java.awt.event.FocusEvent;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This simple script traces every AWT focus event in\n * the target process.\n */\n@BTrace\npublic class AWTEventTracer {\n    @OnMethod(\n            clazz = \"java.awt.EventQueue\",\n            method = \"dispatchEvent\"\n    )\n    public static void onevent(@Self EventQueue queue, AWTEvent event) {\n        if (event instanceof FocusEvent) {\n            println(event);\n            println();\n        }\n    }\n}\n\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllCalls1.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This script demonstrates the possibility to intercept\n * method calls that are about to be executed from the body of\n * a certain method. This is achieved by using the {@linkplain Kind#CALL}\n * location value.\n */\n@BTrace\npublic class AllCalls1 {\n    @OnMethod(clazz = \"javax.swing.JTextField\", method = \"/.*/\",\n            location = @Location(value = Kind.CALL, clazz = \"/.*/\", method = \"/.*/\"))\n    public static void m(@Self Object self, @TargetMethodOrField String method, @ProbeMethodName String probeMethod) { // all calls to the methods with signature \"()\"\n        println(method + \" in \" + probeMethod);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllCalls1Sampled.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This script demonstrates the possibility to intercept\n * method calls that are about to be executed from the body of\n * a certain method. This is achieved by using the {@linkplain Kind#CALL}\n * location value.\n * <p>\n * Not all instances of the method call are intercepted, however. Adaptive sampling\n * is used to balance the captured data and incurred overhead.\n */\n@BTrace\npublic class AllCalls1Sampled {\n    @OnMethod(clazz = \"javax.swing.JTextField\", method = \"/.*/\",\n            location = @Location(value = Kind.CALL, clazz = \"/.*/\", method = \"/.*/\"))\n    @Sampled(kind = Sampled.Sampler.Adaptive)\n    public static void m(@Self Object self, @TargetMethodOrField String method, @ProbeMethodName String probeMethod) { // all calls to the methods with signature \"()\"\n        println(method + \" in \" + probeMethod);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllCalls2.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This script demonstrates the possibility to intercept\n * method calls that are about to be executed from the body of\n * a certain method. This is achieved by using the {@linkplain Kind#CALL}\n * location value.\n */\n@BTrace\npublic class AllCalls2 {\n    @OnMethod(clazz = \"/javax\\\\.swing\\\\..*/\", method = \"/.*/\",\n            location = @Location(value = Kind.CALL, clazz = \"/.*/\", method = \"/.*/\"))\n    public static void n(@Self Object self, @ProbeClassName String pcm, @ProbeMethodName String pmn,\n                         @TargetInstance Object instance, @TargetMethodOrField String method, String text) { // all calls to the methods with signature \"(String)\"\n        println(\"Context: \" + pcm + \"#\" + pmn + method + \" \" + text);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllCalls2Sampled.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This script demonstrates the possibility to intercept\n * method calls that are about to be executed from the body of\n * a certain method. This is achieved by using the {@linkplain Kind#CALL}\n * location value.\n * <p>\n * Not all instances of the method call are intercepted, however.  Sampling\n * is used to pick only statistically representative ones.\n */\n@BTrace\npublic class AllCalls2Sampled {\n    @OnMethod(clazz = \"/javax\\\\.swing\\\\..*/\", method = \"/.*/\",\n            location = @Location(value = Kind.CALL, clazz = \"/.*/\", method = \"/.*/\"))\n    @Sampled\n    public static void n(@Self Object self, @ProbeClassName String pcm, @ProbeMethodName String pmn,\n                         @TargetInstance Object instance, @TargetMethodOrField String method, String text) { // all calls to the methods with signature \"(String)\"\n        println(\"Context: \" + pcm + \"#\" + pmn + method + \" \" + text);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllCalls3.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.types.AnyType;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.printArray;\n\n/**\n * This script demonstrates the possibility to intercept\n * method calls that are about to be executed from the body of\n * a certain method. This is achieved by using the {@linkplain Kind#CALL}\n * location value.\n */\n@BTrace\npublic class AllCalls3 {\n    @OnMethod(clazz = \"javax.swing.JButton\", method = \"/.*/\",\n            location = @Location(value = Kind.CALL, clazz = \"/.*/\", method = \"/.*/\"))\n    public static void o(@Self Object self, @ProbeMethodName String pmn, AnyType[] args) { // all calls to methods\n        // self - this for the method call\n        // pmn - textual representation of the method\n        // contents of args array:\n        // [0]..[n] - original method call arguments\n        printArray(args);\n    }\n} \n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllCalls3Sampled.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.types.AnyType;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.printArray;\n\n/**\n * This script demonstrates the possibility to intercept\n * method calls that are about to be executed from the body of\n * a certain method. This is achieved by using the {@linkplain Kind#CALL}\n * location value.\n * <p>\n * Not all instances of the method call are intercepted, however. Adaptive sampling\n * is used to balance the captured data and incurred overhead.\n */\n@BTrace\npublic class AllCalls3Sampled {\n    @OnMethod(clazz = \"javax.swing.JButton\", method = \"/.*/\",\n            location = @Location(value = Kind.CALL, clazz = \"/.*/\", method = \"/.*/\"))\n    @Sampled(kind = Sampled.Sampler.Adaptive)\n    public static void o(@Self Object self, @ProbeMethodName String pmn, AnyType[] args) { // all calls to methods\n        // self - this for the method call\n        // pmn - textual representation of the method\n        // contents of args array:\n        // [0]..[n] - original method call arguments\n        printArray(args);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllLines.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\n\nimport static org.openjdk.btrace.core.BTraceUtils.print;\n\n/*\n * This sample prints a line every time any line\n * of code of java.lang.Thread class is reached.\n * The line param may be set to any particular\n * value so that the probe fires only when that line\n * is reached. But, the value -1 means all line numbers.\n */\n@BTrace\npublic class AllLines {\n    @OnMethod(\n            clazz = \"java.lang.Thread\",\n            location = @Location(value = Kind.LINE, line = -1)\n    )\n    public static void online(@ProbeClassName String pcn, @ProbeMethodName String pmn, int line) {\n        print(pcn + \".\" + pmn + \":\" + line);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllMethods.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Injected;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.services.impl.Printer;\n\n/**\n * This script traces method entry into every method of\n * every class in javax.swing package! Think before using\n * this script -- this will slow down your app significantly!!\n */\n@BTrace\npublic class AllMethods {\n    @Injected\n    private static Printer printer;\n\n    @OnMethod(\n            clazz = \"/javax\\\\.swing\\\\..*/\",\n            method = \"${m}\"\n    )\n    public static void m(@Self Object o, @ProbeClassName String probeClass, @ProbeMethodName String probeMethod) {\n        printer.println(\"this = \" + o);\n        printer.print(\"entered \" + probeClass);\n        printer.println(\".\" + probeMethod);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllMethods1.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * This script traces method entry into every method of\n * every class in javax.swing package! Think before using\n * this script -- this will slow down your app significantly!!\n */\n@BTrace\npublic class AllMethods1 {\n    @OnMethod(\n            clazz = \"/javax\\\\.swing\\\\..*/\",\n            method = \"/.*/\"\n    )\n    public static void m(@Self Object o, @ProbeClassName String probeClass, @ProbeMethodName String probeMethod) {\n        println(\"this = \" + o);\n        print(\"entered \" + probeClass);\n        println(\".\" + probeMethod);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllMethodsLevels.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnEvent;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This script traces method entry into every method of\n * every class in javax.swing package! Think before using\n * this script -- this will slow down your app significantly!!\n */\n@BTrace\npublic class AllMethodsLevels {\n    /**\n     * Capturing only methods invoked from javax.swing.JComponent class.\n     */\n    @OnMethod(\n            clazz = \"javax.swing.JComponent\",\n            method = \"/.*/\",\n            enableAt = @Level(\"=0\")\n    )\n    public static void l0(@ProbeMethodName(fqn = true) String probeMethod) {\n        println(\"# \" + probeMethod);\n    }\n\n    /**\n     * This will intercept all the methods from javax.swing.* classes.\n     */\n    @OnMethod(\n            clazz = \"/javax\\\\.swing\\\\.*/\",\n            method = \"/.*/\",\n            enableAt = @Level(\">=1\")\n    )\n    public static void l1(@ProbeMethodName(fqn = true) String probeMethod) {\n        println(\"## \" + probeMethod);\n    }\n\n    /**\n     * Switch to level 0.\n     */\n    @OnEvent(\"l0\")\n    public static void setL0() {\n        BTraceUtils.setInstrumentationLevel(0);\n    }\n\n    /**\n     * Swtitch to level 1.\n     */\n    @OnEvent(\"l1\")\n    public static void setL1() {\n        BTraceUtils.setInstrumentationLevel(1);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllMethodsSampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.print;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This script traces method entry into every method of\n * every class in javax.swing package. Think before using\n * this script -- this will slow down your app significantly!!\n * <p>\n * Not all calls are intercepted, however. Sampling\n * is used to pick only statistically representative ones.\n */\n@BTrace\npublic class AllMethodsSampled {\n    @OnMethod(\n            clazz = \"/javax\\\\.swing\\\\..*/\",\n            method = \"/.*/\"\n    )\n    @Sampled\n    public static void m(@Self Object o, @ProbeClassName String probeClass, @ProbeMethodName String probeMethod) {\n        println(\"this = \" + o);\n        print(\"entered \" + probeClass);\n        println(\".\" + probeMethod);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/AllSync.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Where;\n\nimport static org.openjdk.btrace.core.BTraceUtils.identityStr;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This script traces method/block entry into every method of\n * every class in javax.swing package! Think before using\n * this script -- this will slow down your app significantly!!\n * Note tha Where.BEFORE is default. For synchronized blocks, BEFORE\n * means before \"monitorenter\" bytecode. For synchronized methods, we\n * can not have probe point Where.BEFORE. Lock is acquired before entering\n * synchronized method. By making the probe point Where.AFTER for SYNC_ENTER,\n * we probe after monitorenter bytecode or synchronized method entry.\n */\n@BTrace\npublic class AllSync {\n    @OnMethod(\n            clazz = \"/javax\\\\.swing\\\\..*/\",\n            method = \"/.*/\",\n            location = @Location(value = Kind.SYNC_ENTRY, where = Where.AFTER)\n    )\n    public static void onSyncEntry(Object obj) {\n        println(\"after synchronized entry: \" + identityStr(obj));\n    }\n\n    @OnMethod(\n            clazz = \"/javax\\\\.swing\\\\..*/\",\n            method = \"/.*/\",\n            location = @Location(Kind.SYNC_EXIT)\n    )\n    public static void onSyncExit(Object obj) {\n        println(\"before synchronized exit: \" + identityStr(obj));\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/ArgArray.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.types.AnyType;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\n\nimport static org.openjdk.btrace.core.BTraceUtils.printArray;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This sample demonstrates regular expression\n * probe matching and getting input arguments\n * as an array - so that any overload variant\n * can be traced in \"one place\". This example\n * traces any \"readXX\" method on any class in\n * java.io package. Probed class, method and arg\n * array is printed in the action.\n */\n@BTrace\npublic class ArgArray {\n    @OnMethod(\n            clazz = \"/java\\\\.io\\\\..*/\",\n            method = \"/read.*/\"\n    )\n    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) {\n        println(pcn);\n        println(pmn);\n        printArray(args);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/Classload.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * A simple BTrace program that prints stack trace\n * whenever a class is loaded by a user-defined\n * class loader. We insert a return point probe in\n * ClassLoader.defineClass method to detect successful\n * class load.\n */\n@BTrace\npublic class Classload {\n    @OnMethod(\n            clazz = \"+java.lang.ClassLoader\",\n            method = \"defineClass\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void defineclass(@Return Class<?> cl) {\n        println(\"loaded \" + Reflective.name(cl));\n        Threads.jstack();\n        println(\"==========================\");\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/CommandArg.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * This BTrace program demonstrates command line\n * arguments. $ method helps in getting command line\n * arguments. In this example, desired thread name is\n * passed from the command line (of the BTrace client).\n */\n@BTrace\npublic class CommandArg {\n    @OnMethod(\n            clazz = \"java.lang.Thread\",\n            method = \"run\"\n    )\n    public static void started() {\n        if (Strings.strcmp(Threads.name(Threads.currentThread()), Sys.$(2)) == 0) {\n            println(\"started \" + Sys.$(2));\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/DTraceInline.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.DTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/*\n * This sample demonstrates DTrace/BTrace integration.\n * A one-liner D-script is started by BTrace client\n * because of @DTrace annotation. In this example\n * on new Java Thread starts, BTrace action raises a\n * DTrace probe. The D-script prints mixed mode stack\n * trace on receiving this probe.\n */\n@DTrace(\"btrace$1:::event / copyinstr(arg0) == \\\"mstack\\\" / { jstack(); }\")\n@BTrace\npublic class DTraceInline {\n    @OnMethod(\n            clazz = \"java.lang.Thread\",\n            method = \"start\"\n    )\n    public static void newThread(Thread th) {\n        println(Threads.name(th));\n        D.probe(\"mstack\", \"\");\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/DTraceRefDemo.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.DTraceRef;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/*\n * This sample demonstrates associating a D-script\n * with a BTrace program using @DTraceRef annotation.\n * BTrace client looks for absolute or relative path for\n * the D-script and submits it to kernel *before* submitting\n * BTrace program to BTrace agent.\n */\n@DTraceRef(\"classload.d\")\n@BTrace\npublic class DTraceRefDemo {\n    @OnMethod(\n            clazz = \"java.lang.ClassLoader\",\n            method = \"defineClass\"\n    )\n    public static void defineClass() {\n        println(\"user defined loader load start\");\n    }\n\n    @OnMethod(\n            clazz = \"java.lang.ClassLoader\",\n            method = \"defineClass\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void defineclass(Class<?> cl) {\n        println(\"loaded \" + Reflective.name(cl));\n        Threads.jstack();\n        println(\"==========================\");\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/Deadlock.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnTimer;\n\nimport static org.openjdk.btrace.core.BTraceUtils.Threads.deadlocks;\n\n/**\n * This BTrace program demonstrates deadlocks\n * built-in function. This example prints\n * deadlocks (if any) once every 4 seconds.\n */\n@BTrace\npublic class Deadlock {\n    @OnTimer(4000)\n    public static void print() {\n        deadlocks();\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/FileTracker.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TLS;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * This sample prints all files opened for read/write\n * by a Java process. Note that if you pass FileDescriptor\n * to File{Input/Output}Stream or File{Reader/Writer},\n * that is not tracked by this script.\n */\n@BTrace\npublic class FileTracker {\n    @TLS\n    private static String name;\n\n    @OnMethod(\n            clazz = \"java.io.FileInputStream\",\n            method = \"<init>\"\n    )\n    public static void onNewFileInputStream(@Self FileInputStream self, File f) {\n        name = Strings.str(f);\n    }\n\n    @OnMethod(\n            clazz = \"java.io.FileInputStream\",\n            method = \"<init>\",\n            type = \"void (java.io.File)\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void onNewFileInputStreamReturn() {\n        if (name != null) {\n            println(\"opened for read \" + name);\n            name = null;\n        }\n    }\n\n    @OnMethod(\n            clazz = \"java.io.FileOutputStream\",\n            method = \"<init>\"\n    )\n    public static void onNewFileOutputStream(@Self FileOutputStream self, File f, boolean b) {\n        name = str(f);\n    }\n\n    @OnMethod(\n            clazz = \"java.io.FileOutputStream\",\n            method = \"<init>\",\n            type = \"void (java.io.File, boolean)\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void OnNewFileOutputStreamReturn() {\n        if (name != null) {\n            println(\"opened for write \" + name);\n            name = null;\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/FileTrackerJfr.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Event;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TLS;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\nimport static org.openjdk.btrace.core.BTraceUtils.Jfr.*;\n\n/**\n * This sample prints all files opened for read/write\n * by a Java process. Note that if you pass FileDescriptor\n * to File{Input/Output}Stream or File{Reader/Writer},\n * that is not tracked by this script.\n */\n@BTrace\npublic class FileTrackerJfr {\n    @Event(\n            name = \"fileEvent\",\n            label = \"BTrace File Event\",\n            description = \"Sample BTrace file tracker\",\n            category = {\"btrace\", \"samples\"},\n            fields = {\n                    @Event.Field(type = Event.FieldType.STRING, name = \"fileName\"),\n                    @Event.Field(type = Event.FieldType.STRING, name = \"operation\")\n            }\n    )\n    private static JfrEvent.Factory eventFactory;\n\n    @TLS\n    private static String name;\n\n    @OnMethod(\n            clazz = \"java.io.FileInputStream\",\n            method = \"<init>\"\n    )\n    public static void onNewFileInputStream(@Self FileInputStream self, File f) {\n        name = Strings.str(f);\n    }\n\n    @OnMethod(\n            clazz = \"java.io.FileInputStream\",\n            method = \"<init>\",\n            type = \"void (java.io.File)\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void onNewFileInputStreamReturn() {\n        if (name != null) {\n            JfrEvent event = prepareEvent(eventFactory);\n            setEventField(event, \"fileName\", name);\n            setEventField(event, \"operation\", \"read\");\n            commit(event);\n            name = null;\n        }\n    }\n\n    @OnMethod(\n            clazz = \"java.io.FileOutputStream\",\n            method = \"<init>\"\n    )\n    public static void onNewFileOutputStream(@Self FileOutputStream self, File f, boolean b) {\n        name = str(f);\n    }\n\n    @OnMethod(\n            clazz = \"java.io.FileOutputStream\",\n            method = \"<init>\",\n            type = \"void (java.io.File, boolean)\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void OnNewFileOutputStreamReturn() {\n        if (name != null) {\n            JfrEvent event = prepareEvent(eventFactory);\n            setEventField(event, \"fileName\", name);\n            setEventField(event, \"operation\", \"write\");\n            commit(event);\n            name = null;\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/FinalizeTracker.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.OnTimer;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport java.lang.reflect.Field;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n@BTrace\npublic class FinalizeTracker {\n    private static Field fdField =\n            field(\"java.io.FileInputStream\", \"fd\");\n\n    @OnTimer(4000)\n    public static void ontimer() {\n        runFinalization();\n    }\n\n    @OnMethod(\n            clazz = \"java.io.FileInputStream\",\n            method = \"finalize\"\n    )\n    public static void onfinalize(@Self Object me) {\n        println(concat(\"finalizing \", str(me)));\n        printFields(me);\n        printFields(get(fdField, me));\n        println(\"==========\");\n    }\n\n    @OnMethod(\n            clazz = \"java.io.FileInputStream\",\n            method = \"close\"\n    )\n    public static void onclose(@Self Object me) {\n        println(concat(\"closing \", str(me)));\n        println(concat(\"thread: \", str(currentThread())));\n        printFields(me);\n        printFields(get(fdField, me));\n        jstack();\n        println(\"=============\");\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/HistoOnEvent.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnEvent;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * This sample collects histogram of javax.swing.JComponets\n * created by traced app. But, the histogram is printed only\n * on event (from client).\n */\n@BTrace\npublic class HistoOnEvent {\n    private static Map<String, AtomicInteger> histo = newHashMap();\n\n    @OnMethod(\n            clazz = \"javax.swing.JComponent\",\n            method = \"<init>\"\n    )\n    public static void onnewObject(@Self Object obj) {\n        String cn = name(classOf(obj));\n        AtomicInteger ai = get(histo, cn);\n        if (ai == null) {\n            ai = newAtomicInteger(1);\n            put(histo, cn, ai);\n        } else {\n            incrementAndGet(ai);\n        }\n    }\n\n    @OnEvent\n    public static void print() {\n        if (size(histo) != 0) {\n            printNumberMap(\"Component Histogram\", histo);\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/Histogram.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.OnTimer;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * This sample collects histogram of javax.swing.JComponets\n * created by traced app. The histogram is printed once\n * every 4 seconds.\n */\n@BTrace\npublic class Histogram {\n    private static Map<String, AtomicInteger> histo = Collections.newHashMap();\n\n    @OnMethod(\n            clazz = \"javax.swing.JComponent\",\n            method = \"<init>\"\n    )\n    public static void onnewObject(@Self Object obj) {\n        String cn = Reflective.name(classOf(obj));\n        AtomicInteger ai = Collections.get(histo, cn);\n        if (ai == null) {\n            ai = Atomic.newAtomicInteger(1);\n            Collections.put(histo, cn, ai);\n        } else {\n            Atomic.incrementAndGet(ai);\n        }\n    }\n\n    @OnTimer(4000)\n    public static void print() {\n        if (Collections.size(histo) != 0) {\n            printNumberMap(\"Component Histogram\", histo);\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/HistogramBean.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.OnTimer;\nimport org.openjdk.btrace.core.annotations.Property;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * This sample collects histogram of javax.swing.JComponets\n * created by traced app. The histogram is printed once\n * every 4 seconds. Also, this example exposes the trace class\n * as a JMX bean. After connecting BTrace to the target\n * application, connect VisualVM or jconsole or any other\n * JMX client to the same application.\n */\n@BTrace\npublic class HistogramBean {\n    // @Property exposes this field as MBean attribute\n    @Property\n    private static Map<String, AtomicInteger> histo = newHashMap();\n\n    @OnMethod(\n            clazz = \"javax.swing.JComponent\",\n            method = \"<init>\"\n    )\n    public static void onnewObject(@Self Object obj) {\n        String cn = name(classOf(obj));\n        AtomicInteger ai = get(histo, cn);\n        if (ai == null) {\n            ai = newAtomicInteger(1);\n            put(histo, cn, ai);\n        } else {\n            incrementAndGet(ai);\n        }\n    }\n\n    @OnTimer(4000)\n    public static void print() {\n        if (size(histo) != 0) {\n            printNumberMap(\"Component Histogram\", histo);\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/JInfo.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/*\n * A simple sample that prints system properties, flags and exits.\n * This BTrace program mimics the jinfo command line tool in JDK.\n */\n@BTrace\npublic class JInfo {\n    static {\n        println(\"System Properties:\");\n        printProperties();\n        println(\"VM Flags:\");\n        printVmArguments();\n        println(\"OS Enviroment:\");\n        printEnv();\n        exit(0);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/JMap.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\n\nimport static org.openjdk.btrace.core.BTraceUtils.Sys;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/*\n * A simple sample that dumps heap of the target at start and exits.\n * This BTrace program mimics the jmap tool (with -dump option).\n */\n@BTrace\npublic class JMap {\n    static {\n        String name;\n        if (Sys.$length() == 3) {\n            name = Sys.$(2);\n        } else {\n            name = \"heap.bin\";\n        }\n        Sys.Memory.dumpHeap(name);\n        println(\"heap dumped!\");\n        Sys.exit(0);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/JStack.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\n\nimport static org.openjdk.btrace.core.BTraceUtils.Sys.exit;\nimport static org.openjdk.btrace.core.BTraceUtils.Threads.deadlocks;\nimport static org.openjdk.btrace.core.BTraceUtils.Threads.jstackAll;\n\n/*\n * A simple sample prints stack traces and exits. This\n * BTrace program mimics the jstack command line tool in JDK.\n */\n@BTrace\npublic class JStack {\n    static {\n        deadlocks(false);\n        jstackAll();\n        exit(0);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/LogTracer.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport java.lang.reflect.Field;\nimport java.util.logging.LogRecord;\nimport java.util.logging.Logger;\n\nimport static org.openjdk.btrace.core.BTraceUtils.Reflective;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * Simple log message tracer class. This class\n * prints all log messages regardless of log Level.\n * Note that we read LogRecord's private \"message\"\n * field using \"field()\" and \"objectValue()\" built-ins.\n */\n@BTrace\npublic class LogTracer {\n    private static Field msgField = Reflective.field(\"java.util.logging.LogRecord\", \"message\");\n\n    @OnMethod(\n            clazz = \"+java.util.logging.Logger\",\n            method = \"log\"\n    )\n    public static void onLog(@Self Logger self, LogRecord record) {\n        println(Reflective.get(msgField, record));\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/MemAlerter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnLowMemory;\n\nimport java.lang.management.MemoryUsage;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This sample traces memory threshold exceeds.\n * You need to specify the memory pool to watch\n * out and the usage threshold. You can write\n * script that dumps heap by dumpHeap on crossing\n * the threshold instead of just printing a message.\n * Note that the name of the old gen is dependent on\n * GC algorithm. With ParallelGC, the name is \"PS Old Gen\".\n */\n@BTrace\npublic class MemAlerter {\n    @OnLowMemory(\n            pool = \"Tenured Gen\",\n            threshold = 6000000\n    )\n    public static void onLowMem(MemoryUsage mu) {\n        println(mu);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/Memory.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnTimer;\n\nimport static org.openjdk.btrace.core.BTraceUtils.Sys;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * Simple BTrace program that prints memory\n * usage once every 4 seconds. It is possible\n * to modify this to dump heap depending on\n * used memory crossing a threshold or some other\n * such condition. [dumpHeap is a built-in function].\n */\n@BTrace\npublic class Memory {\n    @OnTimer(4000)\n    public static void printMem() {\n        println(\"Heap:\");\n        println(Sys.Memory.heapUsage());\n        println(\"Non-Heap:\");\n        println(Sys.Memory.nonHeapUsage());\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/MultiClass.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This BTrace class demonstrates that we can\n * probe into multiple classes and methods by a\n * single probe specification using regular\n * expressions for class and/or method names as\n * given below. In the example, we put probe into\n * all readXXX methods of all InputStream classes.\n */\n@BTrace\npublic class MultiClass {\n    @OnMethod(\n            clazz = \"/java\\\\.io\\\\..*Input.*/\",\n            method = \"/read.*/\"\n    )\n    public static void onread(@ProbeClassName String pcn) {\n        println(\"read on \" + pcn);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/NewArray.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.OnTimer;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This script demonstrates the possibility to intercept\n * array creations that are about to be executed from the body of\n * a certain method. This is achieved by using the {@linkplain Kind#NEWARRAY}\n * location value.\n */\n@BTrace\npublic class NewArray {\n    // component count\n    private static volatile long count;\n\n    @OnMethod(\n            clazz = \"/.*/\", // tracking in all classes; can be restricted to specific user classes\n            method = \"/.*/\", // tracking in all methods; can be restricted to specific user methods\n            location = @Location(value = Kind.NEWARRAY, clazz = \"char\")\n    )\n    public static void onnew(@ProbeClassName String pcn, @ProbeMethodName String pmn, String arrType, int dim) {\n        // pcn - allocation place class name\n        // pmn - allocation place method name\n        // **** following two parameters MUST always be in this order\n        // arrType - the actual array type\n        // dim - the array dimension\n\n        // increment counter on new array\n        count++;\n    }\n\n    @OnTimer(2000)\n    public static void print() {\n        // print the counter\n        println(\"char[] count = \" + count);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/NewComponent.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.OnTimer;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport java.awt.*;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * A BTrace program that can be run against a GUI\n * program. This program prints (monotonic) count of\n * number of java.awt.Components created once every\n * 2 seconds (2000 milliseconds).\n */\n\n@BTrace\npublic class NewComponent {\n    // component count\n    private static volatile long count;\n\n    @OnMethod(\n            clazz = \"java.awt.Component\",\n            method = \"<init>\"\n    )\n    public static void onnew(@Self Component c) {\n        // increment counter on constructor entry\n        count++;\n    }\n\n    @OnTimer(2000)\n    public static void print() {\n        // print the counter\n        println(\"component count = \" + count);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/OnThrow.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TLS;\n\nimport static org.openjdk.btrace.core.BTraceUtils.Threads;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This example demonstrates printing stack trace\n * of an exception and thread local variables. This\n * trace script prints exception stack trace whenever\n * java.lang.Throwable's constructor returns. This way\n * you can trace all exceptions that may be caught and\n * \"eaten\" silently by the traced program. Note that the\n * assumption is that the exceptions are thrown soon after\n * creation [like in \"throw new FooException();\"] rather\n * that be stored and thrown later.\n */\n@BTrace\npublic class OnThrow {\n    // store current exception in a thread local\n    // variable (@TLS annotation). Note that we can't\n    // store it in a global variable!\n    @TLS\n    static Throwable currentException;\n\n    // introduce probe into every constructor of java.lang.Throwable\n    // class and store \"this\" in the thread local variable.\n    @OnMethod(\n            clazz = \"java.lang.Throwable\",\n            method = \"<init>\"\n    )\n    public static void onthrow(@Self Throwable self) {\n        currentException = self;\n    }\n\n    @OnMethod(\n            clazz = \"java.lang.Throwable\",\n            method = \"<init>\"\n    )\n    public static void onthrow1(@Self Throwable self, String s) {\n        currentException = self;\n    }\n\n    @OnMethod(\n            clazz = \"java.lang.Throwable\",\n            method = \"<init>\"\n    )\n    public static void onthrow1(@Self Throwable self, String s, Throwable cause) {\n        currentException = self;\n    }\n\n    @OnMethod(\n            clazz = \"java.lang.Throwable\",\n            method = \"<init>\"\n    )\n    public static void onthrow2(@Self Throwable self, Throwable cause) {\n        currentException = self;\n    }\n\n    // when any constructor of java.lang.Throwable returns\n    // print the currentException's stack trace.\n    @OnMethod(\n            clazz = \"java.lang.Throwable\",\n            method = \"<init>\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void onthrowreturn() {\n        if (currentException != null) {\n            Threads.jstack(currentException);\n            println(\"=====================\");\n            currentException = null;\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/ProbeArgs.java",
    "content": "/*\n * Copyright (c) 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\n\nimport static org.openjdk.btrace.core.BTraceUtils.Sys;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n@BTrace(trusted = true)\npublic class ProbeArgs {\n    static {\n        println(\"arg#=\" + Sys.$length());\n        for (int i = 0; i < Sys.$length(); i++) {\n            println(\"#\" + i + \"=\" + Sys.$(i));\n        }\n        println(\"switch=\" + Sys.$(\"switch\"));\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/ProbeExit.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnExit;\nimport org.openjdk.btrace.core.annotations.OnTimer;\n\nimport static org.openjdk.btrace.core.BTraceUtils.Sys;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This program demonstrates OnExit probe.\n * When some BTrace action method calls \"exit(int)\"\n * built-in function, method annotated by @OnExit\n * (if found) is called. In this method, BTrace script\n * print summary information of tracing and/or do clean-up.\n */\n\n@BTrace\npublic class ProbeExit {\n    private static volatile int i;\n\n    // @OnExit is called when some BTrace method\n    // calls exit(int) method\n    @OnExit\n    public static void onexit(int code) {\n        println(\"BTrace program exits!\");\n    }\n\n    // We just put @OnTimer probe and exit BTrace\n    // program when the count reaches 5.\n\n    @OnTimer(1000)\n    public static void ontime() {\n        println(\"hello\");\n        i++;\n        if (i == 5) {\n            // note that this exits the BTrace client\n            // and not the traced program (which would\n            // be a destructive action!).\n            Sys.exit(0);\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/Profiling.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.Profiler;\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.OnTimer;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Property;\n\n/**\n * This script demonstrates new capabilities built into BTrace 1.2\n * <ol>\n * <li>Shortened syntax - when omitting \"public\" identifier in the class\n * definition one can safely omit all other modifiers when declaring methods\n * and variables</li>\n * <li>Extended syntax for <b>@ProbeMethodName</b> annotation - you can use\n * <b>fqn</b> parameter to request a fully qualified method name instead of\n * the short one</li>\n * <li>Profiling support - you can use {@linkplain Profiler} instance to gather\n * performance data with the smallest overhead possible\n * </ol>\n *\n * @since 1.2\n */\n@BTrace\nclass Profiling {\n    @Property\n    Profiler swingProfiler = BTraceUtils.Profiling.newProfiler();\n\n    @OnMethod(clazz = \"/javax\\\\.swing\\\\..*/\", method = \"/.*/\")\n    void entry(@ProbeMethodName(fqn = true) String probeMethod) {\n        BTraceUtils.Profiling.recordEntry(swingProfiler, probeMethod);\n    }\n\n    @OnMethod(clazz = \"/javax\\\\.swing\\\\..*/\", method = \"/.*/\", location = @Location(value = Kind.RETURN))\n    void exit(@ProbeMethodName(fqn = true) String probeMethod, @Duration long duration) {\n        BTraceUtils.Profiling.recordExit(swingProfiler, probeMethod, duration);\n    }\n\n    @OnTimer(5000)\n    void timer() {\n        BTraceUtils.Profiling.printSnapshot(\"Swing performance profile\", swingProfiler);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/Sizeof.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n@BTrace\npublic class Sizeof {\n    @OnMethod(\n            clazz = \"javax.swing.JComponent\",\n            method = \"<init>\"\n    )\n    public static void onnew(@Self Object obj) {\n        println(Strings.concat(\"object of: \", Reflective.name(Reflective.classOf(obj))));\n        println(Strings.concat(\"size: \", Strings.str(sizeof(obj))));\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/SocketTracker.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TLS;\n\nimport java.net.InetAddress;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.net.SocketAddress;\nimport java.nio.channels.SocketChannel;\n\nimport static org.openjdk.btrace.core.BTraceUtils.Strings;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This example tracks all server socket creations\n * and client socket accepts.\n * <br>\n * Also, it shows how to use shared methods.\n */\n@BTrace\npublic class SocketTracker {\n    @TLS\n    private static int port = -1;\n    @TLS\n    private static InetAddress inetAddr;\n    @TLS\n    private static SocketAddress sockAddr;\n\n    @OnMethod(\n            clazz = \"java.net.ServerSocket\",\n            method = \"<init>\"\n    )\n    public static void onServerSocket(@Self ServerSocket self,\n                                      int p, int backlog, InetAddress bindAddr) {\n        port = p;\n        inetAddr = bindAddr;\n    }\n\n    @OnMethod(\n            clazz = \"java.net.ServerSocket\",\n            method = \"<init>\",\n            type = \"void (int, int, java.net.InetAddress)\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void onSockReturn() {\n        if (port != -1) {\n            println(\"server socket at \" + port);\n            port = -1;\n        }\n        if (inetAddr != null) {\n            println(\"server socket at \" + inetAddr);\n            inetAddr = null;\n        }\n    }\n\n    @OnMethod(\n            clazz = \"java.net.ServerSocket\",\n            method = \"bind\"\n    )\n    public static void onBind(@Self ServerSocket self, SocketAddress addr, int backlog) {\n        sockAddr = addr;\n    }\n\n    @OnMethod(\n            clazz = \"java.net.ServerSocket\",\n            method = \"bind\",\n            type = \"void (java.net.SocketAddress, int)\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void onBindReturn() {\n        socketBound();\n    }\n\n    @OnMethod(\n            clazz = \"sun.nio.ch.ServerSocketChannelImpl\",\n            method = \"bind\"\n    )\n    public static void onBind(@Self Object self, SocketAddress addr, int backlog) {\n        sockAddr = addr;\n    }\n\n    @OnMethod(\n            clazz = \"sun.nio.ch.ServerSocketChannelImpl\",\n            method = \"bind\",\n            type = \"void (java.net.SocketAddress, int)\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void onBindReturn2() {\n        socketBound();\n    }\n\n    @OnMethod(\n            clazz = \"java.net.ServerSocket\",\n            method = \"accept\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void onAcceptReturn(@Return Socket sock) {\n        clientSocketAcc(sock);\n    }\n\n    @OnMethod(\n            clazz = \"sun.nio.ch.ServerSocketChannelImpl\",\n            method = \"socket\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void onSocket(@Return ServerSocket ssock) {\n        println(Strings.strcat(\"server socket at \", Strings.str(ssock)));\n    }\n\n    @OnMethod(\n            clazz = \"sun.nio.ch.ServerSocketChannelImpl\",\n            method = \"accept\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void onAcceptReturn(@Return SocketChannel sockChan) {\n        clientSocketAcc(sockChan);\n    }\n\n    private static void socketBound() {\n        if (sockAddr != null) {\n            println(\"server socket bind \" + sockAddr);\n            sockAddr = null;\n        }\n    }\n\n    private static void clientSocketAcc(Object obj) {\n        if (obj != null) {\n            println(\"client socket accept \" + obj);\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/SocketTracker1.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.types.AnyType;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.OnProbe;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TLS;\n\nimport java.net.InetAddress;\nimport java.net.ServerSocket;\nimport java.net.SocketAddress;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This example tracks all server socket creations\n * and client socket accepts. Unlike SockerTracker.java,\n * this script uses only public API classes and @OnProbe\n * probes - which would be mapped to internal implementation\n * classes by a XML descriptor at BTrace agent. For this\n * sample, XML probe descriptor is \"java.net.socket.xml\".\n */\n@BTrace\npublic class SocketTracker1 {\n    @TLS\n    private static int port = -1;\n    @TLS\n    private static InetAddress inetAddr;\n    @TLS\n    private static SocketAddress sockAddr;\n\n    @OnMethod(\n            clazz = \"java.net.ServerSocket\",\n            method = \"<init>\"\n    )\n    public static void onServerSocket(@Self ServerSocket self,\n                                      int p, int backlog, InetAddress bindAddr) {\n        port = p;\n        inetAddr = bindAddr;\n    }\n\n    @OnMethod(\n            clazz = \"java.net.ServerSocket\",\n            method = \"<init>\",\n            type = \"void (int, int, java.net.InetAddress)\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void onSockReturn() {\n        if (port != -1) {\n            println(\"server socket at \" + port);\n            port = -1;\n        }\n        if (inetAddr != null) {\n            println(\"server socket at \" + inetAddr);\n            inetAddr = null;\n        }\n    }\n\n    @OnProbe(\n            namespace = \"java.net.socket\",\n            name = \"server-socket-creator\"\n    )\n    public static void onSocket(@Return ServerSocket ssock) {\n        println(\"server socket at \" + ssock);\n    }\n\n    @OnProbe(\n            namespace = \"java.net.socket\",\n            name = \"bind\"\n    )\n    public static void onBind(@Self Object self, SocketAddress addr, int backlog) {\n        sockAddr = addr;\n    }\n\n    @OnProbe(\n            namespace = \"java.net.socket\",\n            name = \"bind-return\"\n    )\n    public static void onBindReturn() {\n        if (sockAddr != null) {\n            println(\"server socket bind \" + sockAddr);\n            sockAddr = null;\n        }\n    }\n\n    @OnProbe(\n            namespace = \"java.net.socket\",\n            name = \"accept-return\"\n    )\n    public static void onAcceptReturn(AnyType sock) {\n        if (sock != null) {\n            println(\"client socket accept \" + sock);\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/SubtypeTracer.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\n\nimport static org.openjdk.btrace.core.BTraceUtils.print;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * A simple example that demonstrates subtype matching by +foo pattern\n * in \"clazz\" attribute of @OnMethod annotation.\n */\n@BTrace\npublic class SubtypeTracer {\n    @OnMethod(\n            clazz = \"+java.lang.Runnable\",\n            method = \"run\"\n    )\n    public static void onRun(@ProbeClassName String pcn, @ProbeMethodName String pmn) {\n        // on every Runnable.run() method entry print class.method\n        print(pcn);\n        print('.');\n        println(pmn);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/SysProp.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.Sys;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This BTrace script demonstrates that it is okay\n * to trace bootstrap classes and call the same\n * inside the trace actions. In this example, we insert\n * a probe into System.getProperty() method and call\n * System.getProperty [through property() built-in function]\n * without getting into infinite recursion. A thread local\n * flag is used by BTrace to avoid infinite recursion here.\n */\n@BTrace\npublic class SysProp {\n    @OnMethod(\n            clazz = \"java.lang.System\",\n            method = \"getProperty\"\n    )\n    public static void onGetProperty(String name) {\n        println(name);\n        // call property safely here.\n        println(Sys.Env.property(name));\n    }\n}\t\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/Test.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.DTraceRef;\n\n@DTraceRef(\"syscalls.d\")\n@BTrace\npublic class Test {\n\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/ThreadBean.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\n\n/*\n * This sample demonstrates simple preprocessor in BTrace.\n * When you run this sample against a Java process, you have\n * to specify -I . option so that the preprocessor can find\n * the \"btracedefs.h\" file:\n *\n *    btrace -I . <pid> ThreadBean.java\n *\n * Without -I option in command, BTrace skips preprocessor\n * invocation.\n */\n#include\"btracedefs.h\"\n\n        BTRACE_IMPORT\n\n/**\n * This sample demonstrates that you can expose a BTrace\n * class as a JMX MBean. After connecting BTrace to the\n * target application, connect VisualVM or jconsole or \n * any other JMX client to the same application.\n */\n        BTRACE ThreadBean{\n\n        // PROPERTY makes the count field to be exposed\n        // as an attribute of this MBean.\n        PROPERTY long count;\n\n@OnMethod(\n        clazz = \"java.lang.Thread\",\n        method = \"start\"\n)\n    ACTION onnewThread(@Self Thread t){\n        count++;\n        }\n\n@OnTimer(2000)\n    ACTION ontimer(){\n            println(count);\n            }\n            }\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/ThreadCounter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Export;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.OnTimer;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.Counters;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This sample creates a jvmstat counter and\n * increments it everytime Thread.start() is\n * called. This thread count may be accessed\n * from outside the process. The @Export annotated\n * fields are mapped to jvmstat counters. The counter\n * name is \"btrace.\" + <className> + \".\" + <fieldName>\n */\n@BTrace\npublic class ThreadCounter {\n\n    // create a jvmstat counter using @Export\n    @Export\n    private static long count;\n\n    @OnMethod(\n            clazz = \"java.lang.Thread\",\n            method = \"start\"\n    )\n    public static void onnewThread(@Self Thread t) {\n        // updating counter is easy. Just assign to\n        // the static field!\n        count++;\n    }\n\n    @OnTimer(2000)\n    public static void ontimer() {\n        // we can access counter as \"count\" as well\n        // as from jvmstat counter directly.\n        println(count);\n        // or equivalently ...\n        println(Counters.perfLong(\"btrace.org.openjdk.btrace.samples.ThreadCounter.count\"));\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/ThreadCounterBean.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.OnTimer;\nimport org.openjdk.btrace.core.annotations.Property;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * This sample demonstrates that you can expose a BTrace\n * class as a JMX MBean. After connecting BTrace to the\n * target application, connect VisualVM or jconsole or\n * any other JMX client to the same application.\n */\n@BTrace\npublic class ThreadCounterBean {\n\n    // @Property makes the count field to be exposed\n    // as an attribute of this MBean.\n    @Property\n    private static long count;\n\n    @OnMethod(\n            clazz = \"java.lang.Thread\",\n            method = \"start\"\n    )\n    public static void onnewThread(@Self Thread t) {\n        count++;\n    }\n\n    @OnTimer(2000)\n    public static void ontimer() {\n        println(count);\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/ThreadStart.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/*\n * This BTrace script inserts a probe into\n * method entry of java.lang.Thread.start() method.\n * At each Thread.start(), it raises a DTrace probe\n * in addition to printing the name of the thread.\n * A D-script like jthread.d may be used to get the\n * associated DTrace probe events.\n */\n@BTrace\npublic class ThreadStart {\n    @OnMethod(\n            clazz = \"java.lang.Thread\",\n            method = \"start\"\n    )\n    public static void onnewThread(@Self Thread t) {\n        D.probe(\"jthreadstart\", Threads.name(t));\n        println(\"starting \" + Threads.name(t));\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/Timers.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnTimer;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * Demonstrates multiple timer probes with different periods to fire.\n */\n@BTrace\npublic class Timers {\n\n    // when starting print the target VM version and start time\n    static {\n        println(\"vm version \" + Sys.VM.vmVersion());\n        println(\"vm starttime \" + Sys.VM.vmStartTime());\n    }\n\n    @OnTimer(1000)\n    public static void f() {\n        println(\"1000 msec: \" + Sys.VM.vmUptime());\n    }\n\n    @OnTimer(3000)\n    public static void f1() {\n        println(\"3000 msec: \" + Time.millis());\n    }\n\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/URLTracker.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.DTraceRef;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.TLS;\n\nimport java.net.Proxy;\nimport java.net.URL;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/*\n * This sample prints every Java URL openURL and\n * openConnection (successful) attempts. In addition,\n * on platforms where DTrace is available, it runs\n * the D-script jurls.d -- which collects a histogram\n * of URL accesses by a btrace:::event probe. From this\n * BTrace program we raise that DTrace probe (dtraceProbe\n * call). Note that it is possible to do similar histogram\n * in BTrace itself (see Histogram.java). But, this sample\n * shows DTrace/BTrace integration as well. On exit, all\n * DTrace aggregates are printed by BTrace (i.e., the ones\n * that are not explicitly printed by DTrace printa call).\n */\n@DTraceRef(\"jurls.d\")\n@BTrace\npublic class URLTracker {\n    @TLS\n    private static URL url;\n\n    @OnMethod(\n            clazz = \"java.net.URL\",\n            method = \"openConnection\"\n    )\n    public static void openURL(URL self) {\n        url = self;\n    }\n\n    @OnMethod(\n            clazz = \"java.net.URL\",\n            method = \"openConnection\"\n    )\n    public static void openURL(URL self, Proxy p) {\n        url = self;\n    }\n\n    @OnMethod(\n            clazz = \"java.net.URL\",\n            method = \"openConnection\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void openURL() {\n        if (url != null) {\n            println(\"open \" + url);\n            D.probe(\"java-url-open\", Strings.str(url));\n            url = null;\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/WebServiceTracker.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * A simple BTrace program that prints a class name\n * and method name whenever a webservice is called and\n * also prints time taken by service method. WebService\n * entry points are annotated javax.jws.WebService and\n * javax.jws.WebMethod. We insert tracing actions into\n * every class and method annotated by these annotations.\n * This way we don't need to know actual webservice\n * implementor class name.\n */\n@BTrace\npublic class WebServiceTracker {\n    @OnMethod(\n            clazz = \"@javax.jws.WebService\",\n            method = \"@javax.jws.WebMethod\"\n    )\n    public static void onWebserviceEntry(@ProbeClassName String pcn, @ProbeMethodName String pmn) {\n        print(\"entering webservice \");\n        println(Strings.strcat(Strings.strcat(pcn, \".\"), pmn));\n    }\n\n    @OnMethod(\n            clazz = \"@javax.jws.WebService\",\n            method = \"@javax.jws.WebMethod\",\n            location = @Location(Kind.RETURN)\n    )\n    public static void onWebserviceReturn(@ProbeClassName String pcn, @ProbeMethodName String pmn, @Duration long d) {\n        print(\"leaving web service \");\n        println(Strings.strcat(Strings.strcat(pcn, \".\"), pmn));\n        println(Strings.strcat(\"Time taken (msec) \", Strings.str(d / 1000)));\n        println(\"==========================\");\n    }\n\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/btracedefs.h",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n\n#define BTRACE_UTILS import static org.openjdk.btrace.core.BTraceUtils.*;\n\n#define BTRACE_ANNO import org.openjdk.btrace.core.annotations.*;\n\n#define BTRACE_IMPORT BTRACE_UTILS \\\n                      BTRACE_ANNO\n\n#define BTRACE @BTrace public class\n\n#define VAR public static\n\n#define ACTION public static void\n\n#define EXPORT @Export public static\n\n#define THREAD @Thread public static \n\n#define PROPERTY @Property public static"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/classload.d",
    "content": "/*\n * This D-script prints one line on each Java class\n * load and unload. To mark DTrace message begin, this\n * script prints a message on DTrace session start.\n */\n\nBEGIN {\n    printf(\"dtrace start\\n\");\n}\n\nhotspot$1:::class-loaded {\n    printf(\"loaded %s\\n\", copyinstr(arg0, arg1));\n}\n\nhotspot$1:::class-unloaded {\n    printf(\"unloaded %s\\n\", copyinstr(arg0, arg1));\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/java.net.socket.xml",
    "content": "<!--\n *\n * Copyright 2008-2010 Sun Microsystems, Inc.  All Rights Reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Sun designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Sun in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,\n * CA 95054 USA or visit www.sun.com if you need additional information or\n * have any questions.\n *\n-->\n<btrace-probes namespace=\"java.net.socket\">\n\n    <probe name=\"server-socket-creator\">\n        <map>\n            <clazz>sun.nio.ch.ServerSocketChannelImpl</clazz>\n            <method>socket</method>\n            <location>\n                <value>RETURN</value>\n            </location>\n        </map>\n    </probe>\n\n    <probe name=\"bind\">\n        <map>\n            <clazz>sun.nio.ch.ServerSocketChannelImpl</clazz>\n            <method>bind</method>\n            <type>void (java.net.SocketAddress, int)</type>\n        </map>\n        <map>\n            <clazz>java.net.ServerSocket</clazz>\n            <method>bind</method>\n            <type>void (java.net.SocketAddress, int)</type>\n        </map>\n    </probe>\n\n    <probe name=\"bind-return\">\n        <map>\n            <clazz>sun.nio.ch.ServerSocketChannelImpl</clazz>\n            <method>bind</method>\n            <type>void (java.net.SocketAddress, int)</type>\n            <location>\n                <value>RETURN</value>\n            </location>\n        </map>\n        <map>\n            <clazz>java.net.ServerSocket</clazz>\n            <method>bind</method>\n            <type>void (java.net.SocketAddress, int)</type>\n            <location>\n                <value>RETURN</value>\n            </location>\n        </map>\n    </probe>\n\n    <probe name=\"accept-return\">\n        <map>\n            <clazz>java.net.ServerSocket</clazz>\n            <method>accept</method>\n            <location>\n                <value>RETURN</value>\n            </location>\n        </map>\n        <map>\n            <clazz>sun.nio.ch.ServerSocketChannelImpl</clazz>\n            <method>accept</method>\n            <location>\n                <value>RETURN</value>\n            </location>\n        </map>\n    </probe>\n\n</btrace-probes>\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/jthread.d",
    "content": "#!/usr/sbin/dtrace -s\n\nbtrace$1:::event \n/ \n  copyinstr(arg0) == \"jthreadstart\" &&\n  arg1 != NULL\n/\n{\n  printf(\"From DTrace: Java Thread '%s' started\\n\", copyinstr(arg1));\n}\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/jurls.d",
    "content": "\n/*\n * This D-script maintains a aggregation whenever\n * btrace:::event probe is raised with \"java-url-open\"\n * as first argument.\n */\nbtrace$target:::event\n/ copyinstr(arg0) == \"java-url-open\" /\n{\n    @[copyinstr(arg1)] = count();\n}\n\n"
  },
  {
    "path": "btrace-dist/src/main/resources/samples/syscalls.d",
    "content": "syscall:::entry \n/ pid == $target /\n{\n   @[probefunc] = count();\n}\n"
  },
  {
    "path": "btrace-dtrace/build.gradle",
    "content": "import org.gradle.internal.os.OperatingSystem\nimport org.gradle.internal.jvm.Jvm\n\nplugins {\n    id 'java'\n    alias(libs.plugins.shadow)\n}\n\ndef nativeHeadersDir = \"${buildDir}/generated/native/include\"\ndef dtraceLibDir = \"${buildDir}/dtrace\"\ndef javaHome = Jvm.current().javaHome\ndef isSolaris = OperatingSystem.current() == OperatingSystem.SOLARIS\ndef osArch = System.getProperty(\"os.arch\")\n\ndependencies {\n    implementation libs.slf4j\n    implementation libs.slf4j.simple\n\n    implementation project(':btrace-core')\n}\n\ntask nativeHeaders(type:Exec) {\n    def classpath = sourceSets.main.runtimeClasspath.asPath\n    commandLine \"javah\", \"-d\", nativeHeadersDir, \"-classpath\", classpath, \"org.openjdk.btrace.core.BTraceRuntime\"\n\n    dependsOn classes\n}\n\nif (isSolaris) {\n    task makedirs(type: Exec) {\n        commandLine \"mkdir\", \"-p\", \"${dtraceLibDir}\", \"${dtraceLibDir}/libs/${osArch}\"\n    }\n    task compileC(type: Exec) {\n        commandLine \"gcc\", \"-c\", \"-I${javaHome}/include\", \"-I${javaHome}/include/solaris\", \"-I${nativeHeadersDir}\", \"-o${dtraceLibDir}/btrace.o\", \"${projectDir}/src/main/native/btrace.c\"\n        dependsOn nativeHeaders, makedirs\n    }\n\n    task dtrace(type: Exec) {\n        commandLine \"/usr/sbin/dtrace\", \"-G\", \"-o\", \"${dtraceLibDir}/btraced.o\", \"-s\", \"${projectDir}/src/main/native/btraced.d\", \"${dtraceLibDir}/btrace.o\"\n        dependsOn compileC, makedirs\n    }\n\n    task linkDTraceLib(type: Exec) {\n        commandLine \"gcc\", \"-G\", \"${dtraceLibDir}/btrace.o\", \"${dtraceLibDir}/btraced.o\", \"-o\", \"${dtraceLibDir}/libs/${osArch}/libbtrace.so\"\n        dependsOn dtrace, makedirs\n    }\n}\n\nsourceSets {\n    main {\n        java {\n            srcDirs \"src/main/java\"\n            srcDirs \"src/mock/java\"\n        }\n    }\n}\n\nshadowJar {\n    include 'org/openjdk/btrace/dtrace/**/*'\n    archiveClassifier = null\n}\n\nsourcesJar {\n    duplicatesStrategy DuplicatesStrategy.EXCLUDE\n}\n\nbuild.dependsOn shadowJar\n\nif (isSolaris) {\n    jar.dependsOn linkDTraceLib\n}\n"
  },
  {
    "path": "btrace-dtrace/src/main/java/org/openjdk/btrace/dtrace/DTrace.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.dtrace;\n\nimport java.io.File;\nimport java.io.IOException;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.openjdk.btrace.core.comm.ErrorCommand;\nimport org.openjdk.btrace.core.comm.MessageCommand;\nimport org.opensolaris.os.dtrace.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Simple wrapper class around DTrace/Java API. This wrapper accepts a BTrace command listener,\n * DTrace file or string and DTrace macro arguments. The events from DTrace are wrapped as BTrace\n * command instances and given to the listener.\n *\n * @author A. Sundararajan\n */\n@SuppressWarnings(\"RedundantThrows\")\npublic class DTrace {\n  private static final Logger log = LoggerFactory.getLogger(DTrace.class);\n\n  /**\n   * Submits a D-script from given file and passes given argument array as DTrace macro arguments.\n   * The events from DTrace are wrapped as BTrace commands and listener given is notified.\n   *\n   * @param file D-script file to submit\n   * @param args DTrace macro arguments\n   * @param listener BTrace command listener that is notified\n   */\n  public static void submit(File file, String[] args, CommandListener listener)\n      throws DTraceException, IOException {\n    Consumer cons = newConsumer(args, listener);\n    cons.compile(file, args);\n    start(cons, listener);\n  }\n\n  /**\n   * Submits a D-script string and passes the given argument array as DTrace macro arguments. The\n   * events from DTrace are wrapped as BTrace commands and listener given is notified.\n   *\n   * @param program D-script as a string\n   * @param args DTrace macro arguments\n   * @param listener BTrace command listener that is notified\n   */\n  public static void submit(String program, String[] args, CommandListener listener)\n      throws DTraceException {\n    Consumer cons = newConsumer(args, listener);\n    cons.compile(program, args);\n    start(cons, listener);\n  }\n\n  private static void start(Consumer cons, CommandListener listener) throws DTraceException {\n    cons.enable();\n    cons.go(\n        th -> {\n          try {\n            listener.onCommand(new ErrorCommand(th));\n          } catch (IOException ioexp) {\n            log.error(\"Failed to send error command to listener\", ioexp);\n          }\n        });\n  }\n\n  private static Consumer newConsumer(String[] args, CommandListener listener)\n      throws DTraceException {\n    Consumer cons = new LocalConsumer();\n    cons.addConsumerListener(\n        new ConsumerAdapter() {\n          private void notify(Command cmd) {\n            try {\n              listener.onCommand(cmd);\n            } catch (IOException ioexp) {\n              log.error(\"Failed to send command to listener\", ioexp);\n            }\n          }\n\n          @Override\n          public void consumerStarted(ConsumerEvent ce) {\n            notify(new DTraceStartCommand(ce));\n          }\n\n          @Override\n          public void consumerStopped(ConsumerEvent ce) {\n            Consumer cons = ce.getSource();\n            Aggregate ag = null;\n            try {\n              ag = cons.getAggregate();\n            } catch (DTraceException dexp) {\n              notify(new ErrorCommand(dexp));\n            }\n            StringBuilder buf = new StringBuilder();\n            if (ag != null) {\n              for (Aggregation agg : ag.asMap().values()) {\n                String name = agg.getName();\n                if (name != null && name.length() > 0) {\n                  buf.append(name);\n                  buf.append('\\n');\n                }\n                for (AggregationRecord rec : agg.asMap().values()) {\n                  buf.append('\\t');\n                  buf.append(rec.getTuple());\n                  buf.append(\" \");\n                  buf.append(rec.getValue());\n                  buf.append('\\n');\n                }\n              }\n            }\n            String msg = buf.toString();\n            if (msg.length() > 0) {\n              notify(new MessageCommand(msg));\n            }\n            notify(new DTraceStopCommand(ce));\n            cons.close();\n          }\n\n          @Override\n          public void dataReceived(DataEvent de) {\n            notify(new DTraceDataCommand(de));\n          }\n\n          @Override\n          public void dataDropped(DropEvent de) {\n            notify(new DTraceDropCommand(de));\n          }\n\n          @Override\n          public void errorEncountered(ErrorEvent ee) throws ConsumerException {\n            try {\n              super.errorEncountered(ee);\n            } catch (ConsumerException ce) {\n              notify(new DTraceErrorCommand(ce, ee));\n              throw ce;\n            }\n          }\n        });\n\n    // open DTrace Consumer\n    cons.open();\n\n    // unused macro arguments are fine\n    cons.setOption(Option.argref, \"\");\n    // if no macro arg passed use \"\" or NULL\n    cons.setOption(Option.defaultargs, \"\");\n    // allow empty D-scripts\n    cons.setOption(Option.empty, \"\");\n    // be quiet! equivalent to DTrace's -q\n    cons.setOption(Option.quiet, \"\");\n    // undefined user land symbols are fine\n    cons.setOption(Option.unodefs, \"\");\n    // allow zero matching of probes (needed for late loading)\n    cons.setOption(Option.zdefs, \"\");\n    try {\n      int pid = Integer.parseInt(args[0]);\n      cons.grabProcess(pid);\n    } catch (Exception ignored) {\n    }\n    return cons;\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/main/java/org/openjdk/btrace/dtrace/DTraceCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.dtrace;\n\n/**\n * A marker interface to tell whether a given BTrace command is a wrapper of a DTrace event.\n *\n * @author A. Sundararajan\n */\npublic interface DTraceCommand {}\n"
  },
  {
    "path": "btrace-dtrace/src/main/java/org/openjdk/btrace/dtrace/DTraceConsumerCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.dtrace;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport org.openjdk.btrace.core.comm.EventCommand;\nimport org.opensolaris.os.dtrace.Consumer;\nimport org.opensolaris.os.dtrace.ConsumerEvent;\n\n/**\n * Abstract command to represent consumer event from DTrace.\n *\n * @author A. Sundararajan\n */\npublic abstract class DTraceConsumerCommand extends EventCommand implements DTraceCommand {\n  private ConsumerEvent ce;\n\n  public DTraceConsumerCommand(String type, ConsumerEvent ce) {\n    super(type);\n    this.ce = ce;\n  }\n\n  /** Returns the underlying DTrace ConsumerEvent. */\n  public ConsumerEvent getConsumerEvent() {\n    return ce;\n  }\n\n  /** Returns the Consumer object. */\n  public Consumer getConsumer() {\n    return ce.getSource();\n  }\n\n  public void write(ObjectOutput out) throws IOException {\n    out.writeObject(ce);\n  }\n\n  public void read(ObjectInput in) throws ClassNotFoundException, IOException {\n    ce = (ConsumerEvent) in.readObject();\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/main/java/org/openjdk/btrace/dtrace/DTraceDataCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.dtrace;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport java.util.List;\nimport org.openjdk.btrace.core.comm.MessageCommand;\nimport org.opensolaris.os.dtrace.DataEvent;\nimport org.opensolaris.os.dtrace.ProbeData;\nimport org.opensolaris.os.dtrace.Record;\n\n/**\n * Command to represent data event from DTrace.\n *\n * @author A. Sundararajan\n */\npublic class DTraceDataCommand extends MessageCommand implements DTraceCommand {\n  private DataEvent de;\n\n  public DTraceDataCommand(DataEvent de) {\n    super(asString(de), true);\n    this.de = de;\n  }\n\n  /** Returns the underlying DTrace DataEvent. */\n  public DataEvent getDataEvent() {\n    return de;\n  }\n\n  public void write(ObjectOutput out) throws IOException {\n    super.write(out);\n    out.writeObject(de);\n  }\n\n  public void read(ObjectInput in) throws ClassNotFoundException, IOException {\n    super.read(in);\n    de = (DataEvent) in.readObject();\n  }\n\n  private static String asString(DataEvent de) {\n    ProbeData pd = de.getProbeData();\n    List<Record> records = pd.getRecords();\n    StringBuilder buf = new StringBuilder();\n    for (Record rec : records) {\n      buf.append(rec);\n    }\n    return buf.toString();\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/main/java/org/openjdk/btrace/dtrace/DTraceDropCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.dtrace;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport org.openjdk.btrace.core.comm.MessageCommand;\nimport org.opensolaris.os.dtrace.DropEvent;\n\n/**\n * Command class that represents DTrace drop event.\n *\n * @author A. Sundararajan\n */\npublic class DTraceDropCommand extends MessageCommand implements DTraceCommand {\n  private DropEvent de;\n\n  public DTraceDropCommand(DropEvent de) {\n    super(asString(de), true);\n    this.de = de;\n  }\n\n  /** Returns the underlying DTrace drop event */\n  public DropEvent getDropEvent() {\n    return de;\n  }\n\n  public void write(ObjectOutput out) throws IOException {\n    super.write(out);\n    out.writeObject(out);\n  }\n\n  public void read(ObjectInput in) throws ClassNotFoundException, IOException {\n    super.read(in);\n    de = (DropEvent) in.readObject();\n  }\n\n  private static String asString(DropEvent de) {\n    return de.getDrop().getDefaultMessage();\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/main/java/org/openjdk/btrace/dtrace/DTraceErrorCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.dtrace;\n\nimport java.io.IOException;\nimport java.io.ObjectInput;\nimport java.io.ObjectOutput;\nimport org.openjdk.btrace.core.comm.ErrorCommand;\nimport org.opensolaris.os.dtrace.ErrorEvent;\n\n/**\n * Command that represents error message from DTrace.\n *\n * @author A. Sundararajan\n */\npublic class DTraceErrorCommand extends ErrorCommand implements DTraceCommand {\n  private ErrorEvent ee;\n\n  public DTraceErrorCommand(Exception exp, ErrorEvent ee) {\n    super(exp);\n    this.ee = ee;\n  }\n\n  /** Returns the underlying DTrace error event. */\n  public ErrorEvent getErrorEvent() {\n    return ee;\n  }\n\n  public void write(ObjectOutput out) throws IOException {\n    super.write(out);\n    out.writeObject(ee);\n  }\n\n  public void read(ObjectInput in) throws ClassNotFoundException, IOException {\n    super.read(in);\n    ee = (ErrorEvent) in.readObject();\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/main/java/org/openjdk/btrace/dtrace/DTraceExtension.java",
    "content": "/*\n * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.dtrace;\n\nimport java.io.File;\nimport java.io.IOException;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.ErrorCommand;\nimport org.openjdk.btrace.core.comm.MessageCommand;\nimport org.openjdk.btrace.core.extensions.Extension;\nimport org.openjdk.btrace.core.extensions.ExtensionContext;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.opensolaris.os.dtrace.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * DTrace extension for BTrace.\n *\n * <p>Provides integration with Solaris DTrace for executing D-scripts from BTrace.\n *\n * <p>Use the following code to obtain an instance:\n *\n * Example usage:\n *\n * <pre><code>\n * {@literal @}Injected\n * private static DTraceExtension dtrace;\n * </code></pre>\n */\npublic final class DTraceExtension extends Extension {\n  private static final Logger log = LoggerFactory.getLogger(DTraceExtension.class);\n\n  private volatile ExtensionContext ctx;\n  private volatile Consumer consumer;\n\n  @Override\n  public void initialize(ExtensionContext ctx) {\n    super.initialize(ctx);\n    this.ctx = ctx;\n  }\n\n  @Override\n  public void close() {\n    Consumer cons = this.consumer;\n    if (cons != null) {\n      try {\n        cons.close();\n      } catch (Exception e) {\n        log.debug(\"Error closing DTrace consumer\", e);\n      }\n      this.consumer = null;\n    }\n  }\n\n  /**\n   * Submits a D-script from the given file.\n   *\n   * @param file D-script file to submit\n   * @param args DTrace macro arguments\n   * @throws DTraceException if compilation or execution fails\n   * @throws IOException if file cannot be read\n   */\n  public void submit(File file, String[] args) throws DTraceException, IOException {\n    Consumer cons = newConsumer(args);\n    cons.compile(file, args);\n    start(cons);\n  }\n\n  /**\n   * Submits a D-script string.\n   *\n   * @param program D-script as a string\n   * @param args DTrace macro arguments\n   * @throws DTraceException if compilation or execution fails\n   */\n  public void submit(String program, String[] args) throws DTraceException {\n    Consumer cons = newConsumer(args);\n    cons.compile(program, args);\n    start(cons);\n  }\n\n  private void start(Consumer cons) throws DTraceException {\n    cons.enable();\n    cons.go(\n        th -> {\n          send(new ErrorCommand(th));\n        });\n  }\n\n  private Consumer newConsumer(String[] args) throws DTraceException {\n    Consumer cons = new LocalConsumer();\n    this.consumer = cons;\n\n    cons.addConsumerListener(\n        new ConsumerAdapter() {\n          @Override\n          public void consumerStarted(ConsumerEvent ce) {\n            send(new DTraceStartCommand(ce));\n          }\n\n          @Override\n          public void consumerStopped(ConsumerEvent ce) {\n            Consumer c = ce.getSource();\n            Aggregate ag = null;\n            try {\n              ag = c.getAggregate();\n            } catch (DTraceException dexp) {\n              send(new ErrorCommand(dexp));\n            }\n            StringBuilder buf = new StringBuilder();\n            if (ag != null) {\n              for (Aggregation agg : ag.asMap().values()) {\n                String name = agg.getName();\n                if (name != null && name.length() > 0) {\n                  buf.append(name);\n                  buf.append('\\n');\n                }\n                for (AggregationRecord rec : agg.asMap().values()) {\n                  buf.append('\\t');\n                  buf.append(rec.getTuple());\n                  buf.append(\" \");\n                  buf.append(rec.getValue());\n                  buf.append('\\n');\n                }\n              }\n            }\n            String msg = buf.toString();\n            if (msg.length() > 0) {\n              send(new MessageCommand(msg));\n            }\n            send(new DTraceStopCommand(ce));\n            c.close();\n          }\n\n          @Override\n          public void dataReceived(DataEvent de) {\n            send(new DTraceDataCommand(de));\n          }\n\n          @Override\n          public void dataDropped(DropEvent de) {\n            send(new DTraceDropCommand(de));\n          }\n\n          @Override\n          public void errorEncountered(ErrorEvent ee) throws ConsumerException {\n            try {\n              super.errorEncountered(ee);\n            } catch (ConsumerException ce) {\n              send(new DTraceErrorCommand(ce, ee));\n              throw ce;\n            }\n          }\n        });\n\n    // open DTrace Consumer\n    cons.open();\n\n    // unused macro arguments are fine\n    cons.setOption(Option.argref, \"\");\n    // if no macro arg passed use \"\" or NULL\n    cons.setOption(Option.defaultargs, \"\");\n    // allow empty D-scripts\n    cons.setOption(Option.empty, \"\");\n    // be quiet! equivalent to DTrace's -q\n    cons.setOption(Option.quiet, \"\");\n    // undefined user land symbols are fine\n    cons.setOption(Option.unodefs, \"\");\n    // allow zero matching of probes (needed for late loading)\n    cons.setOption(Option.zdefs, \"\");\n    if (args != null && args.length > 0) {\n      try {\n        int pid = Integer.parseInt(args[0]);\n        cons.grabProcess(pid);\n      } catch (NumberFormatException e) {\n        log.debug(\"First argument '{}' is not a valid PID, skipping process grab\", args[0]);\n      } catch (Exception e) {\n        log.warn(\"Failed to grab process with PID '{}': {}\", args[0], e.getMessage());\n      }\n    }\n    return cons;\n  }\n\n  private void send(Command cmd) {\n    ExtensionContext c = this.ctx;\n    if (c != null) {\n      c.send(cmd);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/main/java/org/openjdk/btrace/dtrace/DTraceStartCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.dtrace;\n\nimport org.opensolaris.os.dtrace.ConsumerEvent;\n\n/**\n * Command to represent consumer start event from DTrace.\n *\n * @author A. Sundararajan\n */\npublic class DTraceStartCommand extends DTraceConsumerCommand {\n  public DTraceStartCommand(ConsumerEvent ce) {\n    super(\"dtrace-start\", ce);\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/main/java/org/openjdk/btrace/dtrace/DTraceStopCommand.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.dtrace;\n\nimport org.opensolaris.os.dtrace.ConsumerEvent;\n\n/**\n * Command to represent consumer start event from DTrace.\n *\n * @author A. Sundararajan\n */\npublic class DTraceStopCommand extends DTraceConsumerCommand {\n  public DTraceStopCommand(ConsumerEvent ce) {\n    super(\"dtrace-stop\", ce);\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/main/native/btrace.c",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\n#include \"org_openjdk_btrace_core_BTraceRuntime.h\"\n#include <sys/sdt.h>\n\n/*\n * Class:     org_openjdk_btrace_core_BTraceRuntime\n * Method:    dtraceProbe0\n * Signature: (Ljava/lang/String;Ljava/lang/String;II)I\n */\nJNIEXPORT jint JNICALL Java_org_openjdk_btrace_core_BTraceRuntime_dtraceProbe0\n  (JNIEnv *env, jclass cls, jstring str1, jstring str2, jint i1, jint i2) {\n  int result = 0;\n  const char* cstr1;\n  const char* cstr2;\n  if (str1 != NULL) {\n    cstr1 = (*env)->GetStringUTFChars(env, str1, NULL);\n    if (cstr1 == NULL) return 0;\n  } else {\n    cstr1 = NULL;\n  }\n\n  if (str2 != NULL) {\n    cstr2 = (*env)->GetStringUTFChars(env, str2, NULL);\n  } else {\n    cstr2 = NULL;\n  } \n  if (cstr2 == NULL) {\n    if (cstr1) (*env)->ReleaseStringUTFChars(env, str1, cstr1);\n    return 0;\n  }\n\n  DTRACE_PROBE5(btrace, event, cstr1, cstr2, i1, i2, &result);\n\n  if (cstr1) (*env)->ReleaseStringUTFChars(env, str1, cstr1);\n  if (cstr2) (*env)->ReleaseStringUTFChars(env, str2, cstr2);\n  return result;\n}\n"
  },
  {
    "path": "btrace-dtrace/src/main/native/btraced.d",
    "content": "provider btrace {\n  probe event(char* c1, char* c2, int i1, int i2, int* i3);\n};\n"
  },
  {
    "path": "btrace-dtrace/src/main/resources/META-INF/services/org.openjdk.btrace.core.extensions.Extension",
    "content": "org.openjdk.btrace.dtrace.DTraceExtension\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/Aggregate.java",
    "content": "package org.opensolaris.os.dtrace;\n\nimport java.util.Map;\n\n@SuppressWarnings(\"SameReturnValue\")\npublic class Aggregate {\n  public Map<String, Aggregation> asMap() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/Aggregation.java",
    "content": "package org.opensolaris.os.dtrace;\n\nimport java.util.Map;\n\n@SuppressWarnings(\"SameReturnValue\")\npublic class Aggregation {\n  public String getName() {\n    return null;\n  }\n\n  public Map<Tuple, AggregationRecord> asMap() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/AggregationRecord.java",
    "content": "package org.opensolaris.os.dtrace;\n\n@SuppressWarnings(\"SameReturnValue\")\npublic class AggregationRecord {\n  public Tuple getTuple() {\n    return null;\n  }\n\n  public AggregationValue getValue() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/AggregationValue.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic class AggregationValue {}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/Consumer.java",
    "content": "/*\n * CDDL HEADER START\n *\n * The contents of this file are subject to the terms of the\n * Common Development and Distribution License (the \"License\").\n * You may not use this file except in compliance with the License.\n *\n * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE\n * or http://www.opensolaris.org/os/licensing.\n * See the License for the specific language governing permissions\n * and limitations under the License.\n *\n * When distributing Covered Code, include this CDDL HEADER in each\n * file and include the License file at usr/src/OPENSOLARIS.LICENSE.\n * If applicable, add the following below this CDDL HEADER, with the\n * fields enclosed by brackets \"[]\" replaced with your own identifying\n * information: Portions Copyright [yyyy] [name of copyright owner]\n *\n * CDDL HEADER END\n */\n\n/*\n * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.\n * Use is subject to license terms.\n *\n * ident\t\"%Z%%M%\t%I%\t%E% SMI\"\n */\npackage org.opensolaris.os.dtrace;\n\nimport java.io.File;\n\npublic interface Consumer {\n  @SuppressWarnings(\"EmptyMethod\")\n  void open();\n\n  @SuppressWarnings(\"EmptyMethod\")\n  void setOption(String argref, String s);\n\n  @SuppressWarnings(\"EmptyMethod\")\n  void grabProcess(int pid);\n\n  @SuppressWarnings(\"EmptyMethod\")\n  void close();\n\n  @SuppressWarnings({\"SameReturnValue\", \"RedundantThrows\"})\n  Aggregate getAggregate() throws DTraceException;\n\n  @SuppressWarnings(\"EmptyMethod\")\n  void addConsumerListener(ConsumerListener consumerListener);\n\n  @SuppressWarnings(\"EmptyMethod\")\n  void go(ExceptionHandler exceptionHandler);\n\n  @SuppressWarnings(\"EmptyMethod\")\n  void enable();\n\n  @SuppressWarnings(\"EmptyMethod\")\n  void compile(File program, String[] args);\n\n  @SuppressWarnings(\"EmptyMethod\")\n  void compile(String program, String[] args);\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/ConsumerAdapter.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic abstract class ConsumerAdapter implements ConsumerListener {\n  public abstract void consumerStarted(ConsumerEvent ce);\n\n  public abstract void consumerStopped(ConsumerEvent ce);\n\n  public abstract void dataReceived(DataEvent de);\n\n  public abstract void dataDropped(DropEvent de);\n\n  public void errorEncountered(ErrorEvent ee) throws ConsumerException {}\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/ConsumerEvent.java",
    "content": "package org.opensolaris.os.dtrace;\n\n@SuppressWarnings(\"SameReturnValue\")\npublic class ConsumerEvent {\n  public Consumer getSource() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/ConsumerException.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic class ConsumerException extends Exception {}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/ConsumerListener.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic interface ConsumerListener {}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/DTraceException.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic class DTraceException extends Exception {\n  public DTraceException() {}\n\n  public DTraceException(String message) {\n    super(message);\n  }\n\n  public DTraceException(String message, Throwable cause) {\n    super(message, cause);\n  }\n\n  public DTraceException(Throwable cause) {\n    super(cause);\n  }\n\n  public DTraceException(\n      String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {\n    super(message, cause, enableSuppression, writableStackTrace);\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/DataEvent.java",
    "content": "package org.opensolaris.os.dtrace;\n\nimport java.util.EventObject;\n\n@SuppressWarnings(\"SameReturnValue\")\npublic class DataEvent extends EventObject {\n  public DataEvent(Object source) {\n    super(source);\n  }\n\n  public ProbeData getProbeData() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/Drop.java",
    "content": "package org.opensolaris.os.dtrace;\n\n@SuppressWarnings(\"SameReturnValue\")\npublic class Drop {\n  public String getDefaultMessage() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/DropEvent.java",
    "content": "package org.opensolaris.os.dtrace;\n\nimport java.util.EventObject;\n\n@SuppressWarnings(\"SameReturnValue\")\npublic class DropEvent extends EventObject {\n  public DropEvent(Object source) {\n    super(source);\n  }\n\n  public Drop getDrop() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/ErrorEvent.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic class ErrorEvent {}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/ExceptionHandler.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic interface ExceptionHandler {\n  void handleException(Throwable t);\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/LocalConsumer.java",
    "content": "package org.opensolaris.os.dtrace;\n\nimport java.io.File;\n\npublic class LocalConsumer implements Consumer {\n  @Override\n  public void open() {}\n\n  @Override\n  public void setOption(String argref, String s) {}\n\n  @Override\n  public void grabProcess(int pid) {}\n\n  @Override\n  public void close() {}\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  public Aggregate getAggregate() throws DTraceException {\n    return null;\n  }\n\n  @Override\n  public void addConsumerListener(ConsumerListener consumerListener) {}\n\n  @Override\n  public void go(ExceptionHandler exceptionHandler) {}\n\n  @Override\n  public void enable() {}\n\n  @Override\n  public void compile(File program, String[] args) {}\n\n  @Override\n  public void compile(String program, String[] args) {}\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/Option.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic class Option {\n  public static String argref;\n  public static String defaultargs;\n  public static String empty;\n  public static String quiet;\n  public static String unodefs;\n  public static String zdefs;\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/Probe.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic class Probe {}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/ProbeData.java",
    "content": "package org.opensolaris.os.dtrace;\n\nimport java.util.List;\n\n@SuppressWarnings(\"SameReturnValue\")\npublic class ProbeData {\n  public List<Record> getRecords() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/ProbeDescription.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic class ProbeDescription {}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/Program.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic class Program {}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/Record.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic class Record {}\n"
  },
  {
    "path": "btrace-dtrace/src/mock/java/org/opensolaris/os/dtrace/Tuple.java",
    "content": "package org.opensolaris.os.dtrace;\n\npublic class Tuple {}\n"
  },
  {
    "path": "btrace-ext-cli/build.gradle",
    "content": "plugins {\n    id 'java'\n}\n\nrepositories {\n    mavenCentral()\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(11))\n    }\n}\n\ndependencies {\n    implementation project(':btrace-core')\n    implementation project(':btrace-agent')\n    implementation 'com.googlecode.lanterna:lanterna:3.1.5'\n\n    testImplementation platform('org.junit:junit-bom:5.9.1')\n    testImplementation 'org.junit.jupiter:junit-jupiter'\n}\n\ntest {\n    useJUnitPlatform()\n}\n\njar {\n    archiveBaseName.set('btrace-ext-cli')\n    archiveVersion.set('')\n    archiveClassifier.set('')\n    manifest { attributes('Main-Class': 'org.openjdk.btrace.extcli.Main') }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/ExtensionInspector.java",
    "content": "package org.openjdk.btrace.extcli;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.file.*;\nimport java.util.*;\nimport java.util.stream.Stream;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.stream.Collectors;\nimport org.openjdk.btrace.core.extensions.Extension;\nimport org.openjdk.btrace.core.extensions.ExtensionMeta;\nimport org.openjdk.btrace.core.extensions.Permission;\n\nfinal class ExtensionInspector {\n  static ExtensionReport inspect(Path input) throws IOException {\n    if (Files.isDirectory(input)) {\n      Path dir = input;\n      Path api = findFirstDeep(dir, \"-api.jar\");\n      Path impl = findFirstDeep(dir, \"-impl.jar\");\n      if (api == null || impl == null) {\n        return ExtensionReport.error(\"Missing api/impl jars under \" + dir);\n      }\n      String id = readIdFromJar(api);\n      if (id == null || id.isEmpty()) {\n        String n = dir.getFileName() != null ? dir.getFileName().toString() : dir.toString();\n        id = stripVersionFromName(n);\n      }\n      return inspectJars(id, api, impl);\n    } else if (input.toString().endsWith(\".zip\")) {\n      // Derive id from zip file name first; will prefer manifest id if available later\n      String fileName = input.getFileName() != null ? input.getFileName().toString() : input.toString();\n      String id = stripVersionFromName(fileName.replaceFirst(\"-extension\\\\.zip$\", \"\"));\n      try (FileSystem fs = FileSystems.newFileSystem(input, (ClassLoader) null)) {\n        Path root = fs.getPath(\"/\");\n        Path apiIn = findFirstDeep(root, \"-api.jar\");\n        Path implIn = findFirstDeep(root, \"-impl.jar\");\n        if (apiIn == null || implIn == null) {\n          return ExtensionReport.error(\"Missing api/impl jars in zip: \" + input);\n        }\n        Path api = Files.createTempFile(\"btracex-api-\", \".jar\");\n        Path impl = Files.createTempFile(\"btracex-impl-\", \".jar\");\n        Files.copy(apiIn, api, StandardCopyOption.REPLACE_EXISTING);\n        Files.copy(implIn, impl, StandardCopyOption.REPLACE_EXISTING);\n        api.toFile().deleteOnExit();\n        impl.toFile().deleteOnExit();\n        String manifestId = readIdFromJar(api);\n        if (manifestId != null && !manifestId.isEmpty()) id = manifestId;\n        return inspectJars(id, api, impl);\n      }\n    } else {\n      return ExtensionReport.error(\"Invalid input: not a directory or zip: \" + input);\n    }\n  }\n\n  private static Path findFirstDeep(Path root, String suffix) throws IOException {\n    try (Stream<Path> s = Files.walk(root)) {\n      Optional<Path> p = s.filter(pth -> pth.getFileName() != null && pth.getFileName().toString().endsWith(suffix)).findFirst();\n      return p.orElse(null);\n    }\n  }\n\n  private static ExtensionReport inspectJars(String id, Path api, Path impl) throws IOException {\n    List<ExtensionMeta> metas = loadMetasWithoutInstantiating(api, impl);\n    boolean privileged = false;\n    for (ExtensionMeta m : metas) {\n      for (Permission pperm : m.getRequiredPermissions()) {\n        if (pperm.isPrivileged()) { privileged = true; break; }\n      }\n      if (privileged) break;\n    }\n    Set<String> services = readServices(impl);\n    String version = readVersionFromJar(api);\n    if (version == null || version.isEmpty()) {\n      // Fallback: parse from API jar filename, e.g., <id>-<version>-api.jar\n      String n = api.getFileName() != null ? api.getFileName().toString() : api.toString();\n      version = n.replaceFirst(\"^[^-]+-\", \"\").replaceFirst(\"-api\\\\.jar$\", \"\");\n    }\n    List<String> requiredPerms = readPermissionsFromManifestOrProps(api);\n    // Also merge any permissions from impl jar metadata (some extensions declare there)\n    List<String> implPerms = readPermissionsFromManifestOrProps(impl);\n    if (!implPerms.isEmpty()) {\n      LinkedHashSet<String> merged = new LinkedHashSet<>(requiredPerms);\n      merged.addAll(implPerms);\n      requiredPerms = new ArrayList<>(merged);\n    }\n    // Also merge any extension-level permissions from package-level @ExtensionDescriptor\n    if (metas != null) {\n      LinkedHashSet<String> merged = new LinkedHashSet<>(requiredPerms);\n      for (ExtensionMeta m : metas) {\n        for (Permission p : m.getRequiredPermissions()) merged.add(p.name());\n      }\n      requiredPerms = new ArrayList<>(merged);\n    }\n    // Also merge any service-level permissions from @ServiceDescriptor on service interfaces\n    if (services != null && !services.isEmpty()) {\n      try (URLClassLoader cl = new URLClassLoader(new URL[] { api.toUri().toURL(), impl.toUri().toURL() }, ExtensionInspector.class.getClassLoader())) {\n        LinkedHashSet<String> merged = new LinkedHashSet<>(requiredPerms);\n        for (String svc : services) {\n          try {\n            Class<?> sc = Class.forName(svc, false, cl);\n            java.lang.annotation.Annotation sd = sc.getAnnotation(org.openjdk.btrace.core.extensions.ServiceDescriptor.class);\n            if (sd instanceof org.openjdk.btrace.core.extensions.ServiceDescriptor) {\n              for (org.openjdk.btrace.core.extensions.Permission p : ((org.openjdk.btrace.core.extensions.ServiceDescriptor) sd).permissions()) {\n                if (p != null) merged.add(p.name());\n              }\n            }\n          } catch (Throwable ignore) { }\n        }\n        requiredPerms = new ArrayList<>(merged);\n      } catch (Throwable ignore) { }\n    }\n    // Recompute privileged based on the merged permission names\n    if (!privileged) {\n      for (String n : requiredPerms) {\n        try {\n          Permission p = Permission.valueOf(n.trim().toUpperCase());\n          if (p.isPrivileged()) { privileged = true; break; }\n        } catch (IllegalArgumentException ignored) { /* skip unknown names */ }\n      }\n    }\n    return ExtensionReport.ok(id, version, privileged, services, metas, requiredPerms);\n  }\n\n  // Read provider class names from META-INF/services/org.openjdk.btrace.core.extensions.Extension\n  // and load their Class objects without instantiating, then extract metadata.\n  private static List<ExtensionMeta> loadMetasWithoutInstantiating(Path apiJar, Path implJar) {\n    List<ExtensionMeta> result = new ArrayList<>();\n    try (JarFile jf = new JarFile(implJar.toFile())) {\n      JarEntry svc = jf.getJarEntry(\"META-INF/services/\" + Extension.class.getName());\n      if (svc == null) return result;\n      List<String> providers = new ArrayList<>();\n      try (java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(jf.getInputStream(svc), java.nio.charset.StandardCharsets.UTF_8))) {\n        String line;\n        while ((line = br.readLine()) != null) {\n          line = line.trim();\n          if (line.isEmpty() || line.startsWith(\"#\")) continue;\n          providers.add(line);\n        }\n      }\n      URL[] urls = new URL[] { apiJar.toUri().toURL(), implJar.toUri().toURL() };\n      try (URLClassLoader cl = new URLClassLoader(urls, ExtensionInspector.class.getClassLoader())) {\n        for (String cn : providers) {\n          try {\n            Class<?> c = Class.forName(cn, false, cl);\n            if (Extension.class.isAssignableFrom(c)) {\n              @SuppressWarnings(\"unchecked\")\n              Class<? extends Extension> ec = (Class<? extends Extension>) c;\n              result.add(ExtensionMeta.from(ec));\n            }\n          } catch (Throwable t) {\n            // skip faulty provider\n          }\n        }\n      }\n    } catch (Throwable ignored) {}\n    return result;\n  }\n\n  private static Set<String> readServices(Path implJar) {\n    Set<String> services = new HashSet<>();\n    try (JarFile jf = new JarFile(implJar.toFile())) {\n      Enumeration<JarEntry> en = jf.entries();\n      while (en.hasMoreElements()) {\n        JarEntry e = en.nextElement();\n        if (e.getName().startsWith(\"META-INF/services/\") && !e.isDirectory()) {\n          services.add(e.getName().substring(\"META-INF/services/\".length()));\n        }\n      }\n    } catch (IOException ignored) {}\n    return services;\n  }\n\n  private static String readVersionFromJar(Path apiJar) {\n    try (JarFile jf = new JarFile(apiJar.toFile())) {\n      if (jf.getManifest() != null) {\n        String v = jf.getManifest().getMainAttributes().getValue(\"Implementation-Version\");\n        if (v != null) return v;\n        v = jf.getManifest().getMainAttributes().getValue(\"BTrace-Extension-Version\");\n        if (v != null) return v;\n      }\n    } catch (IOException ignored) {}\n    return \"\";\n  }\n\n  private static String readIdFromJar(Path jarPath) {\n    try (JarFile jf = new JarFile(jarPath.toFile())) {\n      Manifest mf = jf.getManifest();\n      if (mf != null) {\n        String id = mf.getMainAttributes().getValue(\"BTrace-Extension-Id\");\n        if (id != null && !id.isEmpty()) return id;\n      }\n      JarEntry props = jf.getJarEntry(\"META-INF/btrace-extension.properties\");\n      if (props != null) {\n        Properties p = new Properties();\n        try (InputStream is = jf.getInputStream(props)) { p.load(is); }\n        String id = p.getProperty(\"extension.id\", \"\");\n        if (!id.isEmpty()) return id;\n      }\n    } catch (IOException ignored) {}\n    return \"\";\n  }\n\n  private static String stripVersionFromName(String name) {\n    if (name == null || name.isEmpty()) return name;\n    // Remove extension suffix if present\n    if (name.endsWith(\".zip\")) name = name.substring(0, name.length() - 4);\n    // Strip trailing version-like segment: last '-' followed by a digit\n    int idx = name.lastIndexOf('-');\n    if (idx > 0 && idx + 1 < name.length() && Character.isDigit(name.charAt(idx + 1))) {\n      return name.substring(0, idx);\n    }\n    return name;\n  }\n\n  private static List<String> readPermissionsFromManifestOrProps(Path jarPath) {\n    List<String> perms = new ArrayList<>();\n    try (JarFile jf = new JarFile(jarPath.toFile())) {\n      Manifest mf = jf.getManifest();\n      if (mf != null) {\n        String v = mf.getMainAttributes().getValue(\"BTrace-Extension-Permissions\");\n        if (v != null && !v.trim().isEmpty()) {\n          for (String part : v.split(\",\")) { String s = part.trim(); if (!s.isEmpty()) perms.add(s); }\n          return perms;\n        }\n      }\n      JarEntry e = jf.getJarEntry(\"META-INF/btrace-extension.properties\");\n      if (e != null) {\n        Properties p = new Properties();\n        try (InputStream is = jf.getInputStream(e)) { p.load(is); }\n        String v = p.getProperty(\"requires.permissions\", \"\");\n        if (!v.isEmpty()) { for (String part : v.split(\",\")) { String s = part.trim(); if (!s.isEmpty()) perms.add(s); } }\n      }\n    } catch (IOException ignored) {}\n    return perms;\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/ExtensionLister.java",
    "content": "package org.openjdk.btrace.extcli;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Path;\nimport java.util.*;\n\nfinal class ExtensionLister {\n  static void list(boolean json) throws IOException {\n    List<Path> roots = new ArrayList<>();\n    String home = System.getenv(\"BTRACE_HOME\");\n    if (home != null) roots.add(Path.of(home, \"extensions\"));\n    roots.add(Path.of(System.getProperty(\"user.home\"), \".btrace\", \"extensions\"));\n    String extra = System.getenv(\"BTRACE_EXT_PATH\");\n    if (extra != null) for (String p : extra.split(File.pathSeparator)) roots.add(Path.of(p));\n\n    List<Object> items = new ArrayList<>();\n    for (Path root : roots) {\n      File rf = root.toFile();\n      if (!rf.exists() || !rf.isDirectory()) continue;\n      File[] dirs = rf.listFiles(File::isDirectory);\n      if (dirs == null) continue;\n      for (File d : dirs) {\n        try {\n          ExtensionReport r = ExtensionInspector.inspect(d.toPath());\n          if (json) items.add(Map.of(\n              \"path\", d.getAbsolutePath(),\n              \"ok\", r.ok,\n              \"id\", r.id,\n              \"privileged\", r.privileged\n          ));\n          else System.out.println((r.ok ? r.id : d.getName()) + (r.privileged ? \" [PRIV]\" : \"\") + \" - \" + d.getAbsolutePath());\n        } catch (IOException e) {\n          if (!json) System.err.println(\"Failed to inspect \" + d + \": \" + e.getMessage());\n        }\n      }\n    }\n    if (json) System.out.println(ExtensionReport.toJson(items));\n  }\n}\n\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/ExtensionReport.java",
    "content": "package org.openjdk.btrace.extcli;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\nimport org.openjdk.btrace.core.extensions.ExtensionMeta;\nimport org.openjdk.btrace.core.extensions.Permission;\n\nfinal class ExtensionReport {\n  final boolean ok;\n  final String message;\n  final String id;\n  final String version;\n  final boolean privileged;\n  final Set<String> services;\n  final List<ExtensionMeta> metas;\n  final List<String> requiredPermNames;\n\n  private ExtensionReport(boolean ok, String message, String id, String version, boolean privileged, Set<String> services, List<ExtensionMeta> metas, List<String> requiredPermNames) {\n    this.ok = ok; this.message = message; this.id = id; this.version = version; this.privileged = privileged; this.services = services; this.metas = metas; this.requiredPermNames = requiredPermNames != null ? requiredPermNames : Collections.emptyList();\n  }\n\n  static ExtensionReport ok(String id, String version, boolean privileged, Set<String> services, List<ExtensionMeta> metas, List<String> requiredPermNames) {\n    return new ExtensionReport(true, \"\", id, version, privileged, services, metas, requiredPermNames);\n  }\n  static ExtensionReport error(String msg) { return new ExtensionReport(false, msg, \"\", \"\", false, Collections.emptySet(), Collections.emptyList(), Collections.emptyList()); }\n\n  public String toString() {\n    if (!ok) return \"ERROR: \" + message;\n    LinkedHashSet<String> permNames = new LinkedHashSet<>(requiredPermNames);\n    if (metas != null) {\n      for (ExtensionMeta m : metas) {\n        for (Permission p : m.getRequiredPermissions()) {\n          permNames.add(p.name());\n        }\n      }\n    }\n    String perms = permNames.stream().sorted().collect(Collectors.joining(\",\"));\n    return String.join(\"\\n\",\n        \"Extension: \" + id,\n        \"Version  : \" + (version == null ? \"\" : version),\n        \"Privileged: \" + privileged,\n        \"Required : [\" + perms + \"]\",\n        \"Services : \" + (services.isEmpty() ? \"(none)\" : String.join(\",\", services))\n    );\n  }\n\n  public String toJson() {\n    Map<String, Object> obj = new LinkedHashMap<>();\n    obj.put(\"ok\", ok);\n    if (!ok) obj.put(\"error\", message);\n    obj.put(\"id\", id);\n    obj.put(\"version\", version);\n    obj.put(\"privileged\", privileged);\n    obj.put(\"services\", new ArrayList<>(services));\n    LinkedHashSet<String> pset = new LinkedHashSet<>(requiredPermNames);\n    if (metas != null) {\n      for (ExtensionMeta m : metas) {\n        for (Permission p : m.getRequiredPermissions()) {\n          pset.add(p.name());\n        }\n      }\n    }\n    obj.put(\"requiredPermissions\", new ArrayList<>(pset));\n    return toJson(obj);\n  }\n\n  static String toJson(Object o) {\n    if (o == null) return \"null\";\n    if (o instanceof String) return '\"' + ((String)o).replace(\"\\\\\", \"\\\\\\\\\").replace(\"\\\"\", \"\\\\\\\"\") + '\"';\n    if (o instanceof Boolean || o instanceof Number) return String.valueOf(o);\n    if (o instanceof Map) {\n      StringBuilder sb = new StringBuilder(); sb.append(\"{\"); boolean first = true;\n      for (Map.Entry<?,?> e : ((Map<?,?>)o).entrySet()) {\n        if (!first) sb.append(','); first = false;\n        sb.append(toJson(String.valueOf(e.getKey()))).append(':').append(toJson(e.getValue()));\n      }\n      return sb.append('}').toString();\n    }\n    if (o instanceof Iterable) {\n      StringBuilder sb = new StringBuilder(); sb.append('['); boolean first = true;\n      for (Object x : (Iterable<?>)o) { if (!first) sb.append(','); first = false; sb.append(toJson(x)); }\n      return sb.append(']').toString();\n    }\n    return toJson(String.valueOf(o));\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/Installer.java",
    "content": "package org.openjdk.btrace.extcli;\n\nimport java.io.BufferedInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URI;\nimport java.net.URL;\nimport java.nio.file.FileSystem;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.stream.Stream;\nimport java.util.Map;\n\nfinal class Installer {\n  private Installer() {}\n\n  static void install(String target, List<String> repos, String id, boolean dryRun) throws Exception {\n    Path zipPath;\n    String derivedId = id;\n\n    if (isUrl(target)) {\n      if (dryRun) {\n        System.out.println(\"[DRY-RUN] Would download: \" + target);\n        return;\n      }\n      zipPath = downloadToTemp(target);\n      derivedId = derivedId != null ? derivedId : deriveIdFromZipName(zipPath.getFileName() != null ? zipPath.getFileName().toString() : zipPath.toString());\n    } else if (target.endsWith(\".zip\") && Files.exists(Path.of(target))) {\n      zipPath = Path.of(target);\n      derivedId = derivedId != null ? derivedId : deriveIdFromZipName(Path.of(target).getFileName().toString());\n    } else if (target.contains(\":\")) {\n      // GAV coordinate: group:artifact:version\n      String[] parts = target.split(\":\");\n      if (parts.length != 3) throw new IllegalArgumentException(\"Invalid coordinate. Expected groupId:artifactId:version\");\n      String groupId = parts[0];\n      String artifactId = parts[1];\n      String version = parts[2];\n      if (derivedId == null) derivedId = artifactId;\n      List<String> candidates = new ArrayList<>();\n      String groupPath = groupId.replace('.', '/');\n      for (String repo : repos) {\n        String base = repo.endsWith(\"/\") ? repo.substring(0, repo.length()-1) : repo;\n        candidates.add(base + \"/\" + groupPath + \"/\" + artifactId + \"/\" + version + \"/\" + artifactId + \"-\" + version + \"-extension.zip\");\n        candidates.add(base + \"/\" + groupPath + \"/\" + artifactId + \"/\" + version + \"/\" + artifactId + \"-\" + version + \".zip\");\n      }\n      if (dryRun) {\n        System.out.println(\"[DRY-RUN] Candidate URLs:\");\n        for (String c : candidates) System.out.println(\"  \" + c);\n        return;\n      }\n      zipPath = tryDownloadAny(candidates);\n      if (zipPath == null) throw new IOException(\"Failed to download extension from provided repositories.\");\n    } else {\n      throw new IllegalArgumentException(\"Unrecognized input: provide a zip path, URL, or group:artifact:version\");\n    }\n\n    // Validate zip contains -api.jar and -impl.jar, and install\n    if (dryRun) {\n      System.out.println(\"[DRY-RUN] Would install zip: \" + zipPath);\n      return;\n    }\n    installZip(zipPath, derivedId);\n  }\n\n  private static boolean isUrl(String s) {\n    return s.startsWith(\"http://\") || s.startsWith(\"https://\");\n  }\n\n  private static Path downloadToTemp(String url) throws IOException {\n    HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();\n    conn.setConnectTimeout(10000);\n    conn.setReadTimeout(20000);\n    conn.setInstanceFollowRedirects(true);\n    int code = conn.getResponseCode();\n    if (code != 200) throw new IOException(\"HTTP \" + code + \" for \" + url);\n    Path tmp = Files.createTempFile(\"btracex-download-\", \".zip\");\n    try (InputStream in = new BufferedInputStream(conn.getInputStream())) {\n      Files.copy(in, tmp, StandardCopyOption.REPLACE_EXISTING);\n    }\n    tmp.toFile().deleteOnExit();\n    return tmp;\n  }\n\n  private static Path tryDownloadAny(List<String> urls) {\n    for (String u : urls) {\n      try {\n        return downloadToTemp(u);\n      } catch (IOException ignored) { }\n    }\n    return null;\n  }\n\n  private static String deriveIdFromZipName(String name) {\n    if (name == null) return \"extension\";\n    // <id>-<version>-extension.zip or <id>-<version>.zip -> <id>\n    String base = name;\n    if (base.endsWith(\"-extension.zip\")) base = base.substring(0, base.length()-\"-extension.zip\".length());\n    else if (base.endsWith(\".zip\")) base = base.substring(0, base.length()-\".zip\".length());\n    int idx = base.lastIndexOf('-');\n    return idx > 0 ? base.substring(0, idx) : base;\n  }\n\n  private static void installZip(Path zipPath, String id) throws IOException {\n    if (id == null || id.isEmpty()) id = deriveIdFromZipName(zipPath.getFileName() != null ? zipPath.getFileName().toString() : zipPath.toString());\n    Path targetRoot = getExtensionsRoot();\n    Path targetDir = targetRoot.resolve(id);\n    Files.createDirectories(targetDir);\n\n    try (FileSystem fs = FileSystems.newFileSystem(zipPath, (ClassLoader) null)) {\n      Path root = fs.getPath(\"/\");\n      // Validate presence of -api.jar and -impl.jar\n      boolean hasApi = false, hasImpl = false;\n      try (Stream<Path> s = Files.walk(root)) {\n        for (Path p : (Iterable<Path>) s::iterator) {\n          if (p.getFileName() == null) continue;\n          String fn = p.getFileName().toString();\n          if (fn.endsWith(\"-api.jar\")) hasApi = true;\n          if (fn.endsWith(\"-impl.jar\")) hasImpl = true;\n        }\n      }\n      if (!hasApi || !hasImpl) throw new IOException(\"Invalid extension zip; missing -api.jar or -impl.jar\");\n      // Copy all contents\n      try (Stream<Path> s = Files.walk(root)) {\n        for (Path p : (Iterable<Path>) s::iterator) {\n          if (Files.isDirectory(p)) continue;\n          Path rel = root.relativize(p);\n          Path dest = targetDir.resolve(rel.toString());\n          Files.createDirectories(dest.getParent());\n          Files.copy(p, dest, StandardCopyOption.REPLACE_EXISTING);\n        }\n      }\n    }\n    System.out.println(\"Installed extension '\" + id + \"' into: \" + targetDir);\n    try {\n      ExtensionReport rep = ExtensionInspector.inspect(targetDir);\n      System.out.println(rep.toString());\n      System.out.println();\n      System.out.println(\"Hint: To enable/disable this extension for implementations, edit your policy:\");\n      System.out.println(\"  btracex policy edit --home\");\n      System.out.println(\"Or set explicitly:\");\n      System.out.println(\"  btracex policy set --allowExtensions \" + id + \" --policy-file ~/.btrace/permissions.properties\");\n      if (rep.privileged) {\n        System.out.println();\n        System.out.println(\"Note: This extension requires privileged permissions. You can allow all privileged extensions with:\");\n        System.out.println(\"  btracex policy set --allowPrivileged true --policy-file ~/.btrace/permissions.properties\");\n      }\n    } catch (Exception ignored) { }\n  }\n\n  private static Path getExtensionsRoot() throws IOException {\n    String home = System.getenv(\"BTRACE_HOME\");\n    if (home != null && !home.isEmpty()) {\n      Path p = Path.of(home, \"extensions\");\n      Files.createDirectories(p);\n      return p;\n    }\n    Path user = Path.of(System.getProperty(\"user.home\"), \".btrace\", \"extensions\");\n    Files.createDirectories(user);\n    return user;\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/Main.java",
    "content": "package org.openjdk.btrace.extcli;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.openjdk.btrace.extcli.tui.ExtRepoBrowser;\n\npublic final class Main {\n  public static void main(String[] args) throws Exception {\n    if (args.length == 0 || Arrays.asList(\"-h\", \"--help\").contains(args[0])) {\n      usage();\n      return;\n    }\n    String cmd = args[0];\n    switch (cmd) {\n      case \"inspect\":\n        if (args.length < 2) {\n          // No argument: open interactive TUI in-process\n          ExtRepoBrowser.launch(Arrays.copyOfRange(args, 1, args.length));\n          break;\n        }\n        boolean json = hasFlag(args, \"--json\");\n        String arg = args[1];\n        ExtensionReport report;\n        Path p = Paths.get(arg);\n        if (Files.exists(p)) {\n          report = ExtensionInspector.inspect(p);\n        } else {\n          Path resolved = RepoScanner.resolveById(arg);\n          if (resolved == null) {\n            err(\"Extension id not found in known repositories: \" + arg);\n            return;\n          }\n          report = ExtensionInspector.inspect(resolved);\n        }\n        if (json) System.out.println(report.toJson()); else System.out.println(report);\n        break;\n      case \"list\":\n        boolean jsonList = hasFlag(args, \"--json\");\n        ExtensionLister.list(jsonList);\n        break;\n      case \"policy\":\n        runPolicy(Arrays.copyOfRange(args, 1, args.length));\n        break;\n      case \"install\":\n        if (args.length < 2) {\n          err(\"Missing coordinate or path. Usage: btracex install <group:artifact:version|zip|url> [--repo <url> ...] [--id <extId>] [--dry-run]\");\n          System.exit(2);\n        }\n        runInstall(Arrays.copyOfRange(args, 1, args.length));\n        break;\n      default:\n        err(\"Unknown command: \" + cmd);\n        usage();\n    }\n  }\n\n  private static void runInstall(String[] args) throws Exception {\n    String target = null;\n    List<String> repos = new ArrayList<>();\n    String id = null;\n    boolean dryRun = false;\n    for (int i = 0; i < args.length; i++) {\n      String a = args[i];\n      if (a.equals(\"--repo\") && i + 1 < args.length) {\n        repos.add(args[++i]);\n      } else if (a.equals(\"--id\") && i + 1 < args.length) {\n        id = args[++i];\n      } else if (a.equals(\"--dry-run\")) {\n        dryRun = true;\n      } else if (a.startsWith(\"--\")) {\n        err(\"Unknown option: \" + a);\n        usage();\n        return;\n      } else if (target == null) {\n        target = a;\n      } else {\n        err(\"Unexpected argument: \" + a);\n        usage();\n        return;\n      }\n    }\n    if (repos.isEmpty()) {\n      repos.add(\"https://repo1.maven.org/maven2\");\n    }\n    if (target == null) {\n      err(\"Missing coordinate or path\");\n      usage();\n      return;\n    }\n    Installer.install(target, repos, id, dryRun);\n  }\n\n  private static void runPolicy(String[] args) throws IOException {\n    if (args.length == 0) {\n      err(\"policy requires a subcommand: print|set|edit\");\n      usage();\n      return;\n    }\n    String sub = args[0];\n    PolicyFile target = PolicyFile.fromArgs(Arrays.copyOfRange(args, 1, args.length));\n    switch (sub) {\n      case \"print\":\n        System.out.println(target.describe(hasFlag(args, \"--json\")));\n        break;\n      case \"set\":\n        target.updateFromArgs(Arrays.copyOfRange(args, 1, args.length));\n        target.save();\n        System.out.println(\"Policy saved to \" + target.getTarget());\n        break;\n      case \"edit\":\n        System.err.println(\"Interactive editor not yet implemented; use 'btracex policy set' for now.\");\n        System.exit(2);\n        break;\n      default:\n        err(\"Unknown policy subcommand: \" + sub);\n        usage();\n    }\n  }\n\n  private static boolean hasFlag(String[] args, String flag) {\n    for (String a : args) if (flag.equals(a)) return true;\n    return false;\n  }\n\n  private static void usage() {\n    System.out.println(\"btracex - BTrace extensions CLI\\n\" +\n        \"Usage:\\n\" +\n        \"  btracex inspect [<path|dir|zip|id>] [--json]  # no args opens repo browser\\n\" +\n        \"  btracex list [--json]\\n\" +\n        \"  btracex policy print [--policy-file <path>|--home|--classpath <outDir>] [--json]\\n\" +\n        \"  btracex policy set [--allowExtensions <ids>] [--denyExtensions <ids>] [--allowPrivileged <bool>] [--policy-file <path>|--home|--classpath <outDir>]\\n\" +\n        \"  btracex install <groupId:artifactId:version> [--repo <url> ...] [--id <extId>] [--dry-run]\\n\");\n  }\n\n  private static void err(String s) { System.err.println(s); }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/PolicyFile.java",
    "content": "package org.openjdk.btrace.extcli;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.*;\nimport java.nio.file.StandardCopyOption;\n\nfinal class PolicyFile {\n  private Path target;\n  private final Properties props = new Properties();\n\n  static PolicyFile fromArgs(String[] args) throws IOException {\n    Path t = null; Path classpathDir = null; boolean home = false;\n    for (int i = 0; i < args.length; i++) {\n      switch (args[i]) {\n        case \"--policy-file\": t = Path.of(args[++i]); break;\n        case \"--home\": home = true; break;\n        case \"--classpath\": classpathDir = Path.of(args[++i]); break;\n      }\n    }\n    if (t != null && (home || classpathDir != null)) throw new IllegalArgumentException(\"Use only one of --policy-file, --home, --classpath\");\n    PolicyFile pf = new PolicyFile();\n    if (t != null) pf.target = t;\n    else if (home) pf.target = Path.of(System.getProperty(\"user.home\"), \".btrace\", \"permissions.properties\");\n    else if (classpathDir != null) pf.target = classpathDir.resolve(\"META-INF/btrace/permissions.properties\");\n    else pf.target = Path.of(System.getProperty(\"user.home\"), \".btrace\", \"permissions.properties\");\n    pf.loadIfExists();\n    return pf;\n  }\n\n  private void loadIfExists() throws IOException {\n    if (Files.exists(target)) try (InputStream is = Files.newInputStream(target)) { props.load(is); }\n  }\n\n  void updateFromArgs(String[] args) {\n    for (int i = 0; i < args.length; i++) {\n      switch (args[i]) {\n        case \"--allowExtensions\": props.setProperty(\"allowExtensions\", args[++i]); break;\n        case \"--denyExtensions\": props.setProperty(\"denyExtensions\", args[++i]); break;\n        case \"--allowPrivileged\": props.setProperty(\"allowPrivileged\", args[++i]); break;\n      }\n    }\n  }\n\n  String describe(boolean json) {\n    Map<String,Object> m = Map.of(\n        \"target\", String.valueOf(target),\n        \"allowExtensions\", props.getProperty(\"allowExtensions\", \"\"),\n        \"denyExtensions\", props.getProperty(\"denyExtensions\", \"\"),\n        \"allowPrivileged\", props.getProperty(\"allowPrivileged\", \"false\")\n    );\n    if (json) return toJson(m);\n    return String.format(\"Policy: %s\\n  allowExtensions=%s\\n  denyExtensions=%s\\n  allowPrivileged=%s\",\n        target, m.get(\"allowExtensions\"), m.get(\"denyExtensions\"), m.get(\"allowPrivileged\"));\n  }\n\n  void save() throws IOException {\n    Files.createDirectories(target.getParent());\n    Path tmp = target.resolveSibling(target.getFileName() + \".tmp\");\n    try (OutputStream os = Files.newOutputStream(tmp)) { props.store(os, \"BTrace permissions policy\"); }\n    Files.move(tmp, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);\n  }\n\n  Path getTarget() { return target; }\n\n  static String toJson(Object o) { return ExtensionReport.toJson(o); }\n\n  List<String> getAllowList() {\n    return splitCsv(props.getProperty(\"allowExtensions\", \"\"));\n  }\n\n  List<String> getDenyList() {\n    return splitCsv(props.getProperty(\"denyExtensions\", \"\"));\n  }\n\n  boolean isAllowed(String id) {\n    return getAllowList().contains(id);\n  }\n\n  boolean isDenied(String id) {\n    return getDenyList().contains(id);\n  }\n\n  void allow(String id) {\n    List<String> allow = new ArrayList<>(getAllowList());\n    if (!allow.contains(id)) allow.add(id);\n    props.setProperty(\"allowExtensions\", String.join(\",\", allow));\n    // remove from deny if present\n    List<String> deny = new ArrayList<>(getDenyList());\n    deny.remove(id);\n    props.setProperty(\"denyExtensions\", String.join(\",\", deny));\n  }\n\n  void deny(String id) {\n    List<String> deny = new ArrayList<>(getDenyList());\n    if (!deny.contains(id)) deny.add(id);\n    props.setProperty(\"denyExtensions\", String.join(\",\", deny));\n    // remove from allow if present\n    List<String> allow = new ArrayList<>(getAllowList());\n    allow.remove(id);\n    props.setProperty(\"allowExtensions\", String.join(\",\", allow));\n  }\n\n  void clear(String id) {\n    List<String> allow = new ArrayList<>(getAllowList());\n    allow.remove(id);\n    props.setProperty(\"allowExtensions\", String.join(\",\", allow));\n    List<String> deny = new ArrayList<>(getDenyList());\n    deny.remove(id);\n    props.setProperty(\"denyExtensions\", String.join(\",\", deny));\n  }\n\n  String headerSummary() {\n    String allowPriv = props.getProperty(\"allowPrivileged\", \"false\");\n    return String.format(\"Policy: %s | allowExtensions=%s | denyExtensions=%s | allowPrivileged=%s\",\n        String.valueOf(target), props.getProperty(\"allowExtensions\", \"\"), props.getProperty(\"denyExtensions\", \"\"), allowPriv);\n  }\n\n  private static List<String> splitCsv(String csv) {\n    List<String> res = new ArrayList<>();\n    if (csv == null || csv.trim().isEmpty()) return res;\n    for (String s : csv.split(\",\")) {\n      String t = s.trim(); if (!t.isEmpty()) res.add(t);\n    }\n    return res;\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/RepoBrowser.java",
    "content": "package org.openjdk.btrace.extcli;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nfinal class RepoBrowser {\n  static void browse() throws IOException { browse(new String[0]); }\n\n  static void browse(String[] args) throws IOException {\n    List<Path> items = new ArrayList<>();\n    for (Path root : RepoScanner.roots()) {\n      if (!Files.isDirectory(root)) continue;\n      try (Stream<Path> s = Files.list(root)) {\n        for (Path p : (Iterable<Path>) s::iterator) {\n          if (Files.isDirectory(p)) items.add(p);\n        }\n      }\n    }\n    if (items.isEmpty()) {\n      System.out.println(\"No extensions found in known repositories.\");\n      return;\n    }\n\n    // Load or create target policy (defaults to home)\n    PolicyFile policy;\n    try {\n      policy = PolicyFile.fromArgs(args);\n    } catch (Exception e) {\n      System.out.println(\"Failed to load policy: \" + e.getMessage());\n      return;\n    }\n\n    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));\n    int sel = 0;\n    while (true) {\n      clearScreen();\n      System.out.println(policy.headerSummary());\n      System.out.println(\"Use Up/Down (or j/k) to move, 'e' to enable/disable, 'i' for details, 'q' to quit.\");\n      System.out.println();\n      for (int i = 0; i < items.size(); i++) {\n        Path dir = items.get(i);\n        String id = dir.getFileName() != null ? dir.getFileName().toString() : String.valueOf(dir);\n        String ver = \"\";\n        try {\n          ExtensionReport r = ExtensionInspector.inspect(dir);\n          if (r != null) {\n            if (r.id != null && !r.id.isEmpty()) id = r.id;\n            if (r.version != null) ver = r.version;\n          }\n        } catch (Exception ignored) { }\n        String verTag = (ver != null && !ver.isEmpty()) ? (\"[\" + ver + \"]\") : \"\";\n        String state = policy.isAllowed(id) ? \"[A]\" : (policy.isDenied(id) ? \"[D]\" : \"[ ]\");\n        String cursor = (i == sel) ? \"->\" : \"  \";\n        System.out.printf(\"%s %s %s%s (%s)%n\", cursor, state, id, verTag, dir);\n      }\n      System.out.print(\"> \");\n      String line = br.readLine();\n      if (line == null) return;\n      if (isUp(line)) { sel = (sel + items.size() - 1) % items.size(); continue; }\n      if (isDown(line)) { sel = (sel + 1) % items.size(); continue; }\n      line = line.trim();\n      if (line.equalsIgnoreCase(\"q\")) return;\n      if (line.equalsIgnoreCase(\"i\")) {\n        showDetails(items.get(sel), br);\n        continue;\n      }\n      if (line.equalsIgnoreCase(\"e\")) {\n        Path dir = items.get(sel);\n        String id = dir.getFileName() != null ? dir.getFileName().toString() : String.valueOf(dir);\n        try {\n          ExtensionReport r = ExtensionInspector.inspect(dir);\n          if (r != null && r.id != null && !r.id.isEmpty()) id = r.id;\n          boolean currentlyAllowed = policy.isAllowed(id);\n          boolean currentlyDenied = policy.isDenied(id);\n          if (currentlyAllowed) {\n            // disable => move to deny\n            policy.deny(id);\n            policy.save();\n          } else if (currentlyDenied) {\n            // enable => move to allow\n            if (confirmEnable(br, r)) { policy.allow(id); policy.save(); }\n          } else {\n            // default => ask to enable\n            if (confirmEnable(br, r)) { policy.allow(id); policy.save(); }\n          }\n        } catch (Exception e) {\n          // ignore\n        }\n        continue;\n      }\n      // If number entered, jump to index\n      try {\n        int idx = Integer.parseInt(line);\n        if (idx >= 0 && idx < items.size()) sel = idx;\n      } catch (NumberFormatException ignored) { }\n    }\n  }\n\n  private static boolean isUp(String line) {\n    return line.contains(\"\\u001B[A\") || line.equalsIgnoreCase(\"k\");\n  }\n  private static boolean isDown(String line) {\n    return line.contains(\"\\u001B[B\") || line.equalsIgnoreCase(\"j\");\n  }\n\n  private static void showDetails(Path dir, BufferedReader br) throws IOException {\n    clearScreen();\n    try {\n      ExtensionReport rep = ExtensionInspector.inspect(dir);\n      System.out.println(rep.toString());\n    } catch (Exception e) {\n      System.out.println(\"Failed to inspect: \" + e.getMessage());\n    }\n    System.out.println();\n    System.out.println(\"(Press Enter to continue)\");\n    br.readLine();\n  }\n\n  private static boolean confirmEnable(BufferedReader br, ExtensionReport rep) throws IOException {\n    clearScreen();\n    if (rep != null) System.out.println(rep.toString());\n    System.out.println();\n    System.out.print(\"Enable this extension? [y/N]: \");\n    String ans = br.readLine();\n    return ans != null && (ans.equalsIgnoreCase(\"y\") || ans.equalsIgnoreCase(\"yes\"));\n  }\n\n  private static void clearScreen() {\n    // Best-effort clear; will just print newlines if ANSI unsupported\n    System.out.print(\"\\033[H\\033[2J\");\n    System.out.flush();\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/RepoScanner.java",
    "content": "package org.openjdk.btrace.extcli;\n\nimport java.io.File;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.List;\n\nfinal class RepoScanner {\n  static List<Path> roots() {\n    List<Path> roots = new ArrayList<>();\n    String home = System.getenv(\"BTRACE_HOME\");\n    if (home != null) roots.add(Path.of(home, \"extensions\"));\n    roots.add(Path.of(System.getProperty(\"user.home\"), \".btrace\", \"extensions\"));\n    String extra = System.getenv(\"BTRACE_EXT_PATH\");\n    if (extra != null) for (String p : extra.split(File.pathSeparator)) roots.add(Path.of(p));\n    return roots;\n  }\n\n  static Path resolveById(String id) {\n    for (Path root : roots()) {\n      Path dir = root.resolve(id);\n      if (dir.toFile().isDirectory()) return dir;\n    }\n    return null;\n  }\n}\n\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/tui/ExtRepoBrowser.java",
    "content": "package org.openjdk.btrace.extcli.tui;\n\n// Copied from client.tui and adapted to ext-cli package\n\nimport com.googlecode.lanterna.SGR;\nimport com.googlecode.lanterna.TerminalSize;\nimport com.googlecode.lanterna.TextColor;\nimport com.googlecode.lanterna.gui2.*;\nimport com.googlecode.lanterna.gui2.table.DefaultTableRenderer;\nimport com.googlecode.lanterna.gui2.table.Table;\nimport com.googlecode.lanterna.gui2.table.TableCellRenderer;\nimport com.googlecode.lanterna.gui2.table.TableHeaderRenderer;\nimport com.googlecode.lanterna.gui2.dialogs.ListSelectDialogBuilder;\nimport com.googlecode.lanterna.gui2.dialogs.MessageDialog;\nimport com.googlecode.lanterna.gui2.dialogs.MessageDialogButton;\nimport com.googlecode.lanterna.gui2.dialogs.TextInputDialogBuilder;\nimport com.googlecode.lanterna.input.KeyStroke;\nimport com.googlecode.lanterna.input.KeyType;\nimport com.googlecode.lanterna.gui2.TextGUIGraphics;\nimport com.googlecode.lanterna.screen.Screen;\nimport com.googlecode.lanterna.terminal.DefaultTerminalFactory;\n\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Supplier;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport java.util.stream.Stream;\n\npublic final class ExtRepoBrowser {\n  private ExtRepoBrowser() {}\n\n  private enum SortKey { STATE, ID, VERSION, PATH }\n  private static final boolean DEBUG_STATE_RENDER = false;\n\n  public static void launch(String[] args) throws Exception {\n    DefaultTerminalFactory factory = new DefaultTerminalFactory();\n    Screen screen = factory.createScreen();\n    screen.startScreen();\n    MultiWindowTextGUI gui = new MultiWindowTextGUI(screen, new DefaultWindowManager(), new EmptySpace());\n\n    final Window window = new BasicWindow(\"BTrace Extensions\");\n    window.setHints(List.of(Window.Hint.FULL_SCREEN));\n\n    Panel root = new Panel(new BorderLayout());\n    Panel headerPanel = new Panel(new LinearLayout(Direction.VERTICAL));\n    headerPanel.setLayoutData(BorderLayout.Location.TOP);\n    Label headerPolicy = new Label(\"\");\n    headerPolicy.setForegroundColor(TextColor.ANSI.WHITE);\n    headerPolicy.setBackgroundColor(TextColor.ANSI.BLUE);\n    Label headerRepos = new Label(\"\");\n    headerRepos.setForegroundColor(TextColor.ANSI.WHITE);\n    headerRepos.setBackgroundColor(TextColor.ANSI.BLUE);\n    headerPanel.addComponent(headerPolicy);\n    headerPanel.addComponent(headerRepos);\n    root.addComponent(headerPanel);\n\n    Panel center = new Panel(new LinearLayout(Direction.VERTICAL));\n\n    PolicyFileLite policy = PolicyFileLite.homeDefault();\n    List<Item> all = new ArrayList<>();\n    TuiState state = TuiState.load();\n    final String[] filterText = new String[] { state.filter == null ? \"\" : state.filter };\n    final SortKey[] sortKey = new SortKey[] { parseSortKey(state.sortKey) };\n    final boolean[] sortAsc = new boolean[] { state.sortAsc };\n    final boolean[] scanning = new boolean[] { false };\n    final double[] splitRatio = new double[] { clampRatio(state.splitRatio) };\n\n    final PolicyFileLite[] polRef = new PolicyFileLite[] { policy };\n    final Label[] detailsRef = new Label[1];\n    final Label[] footerRef = new Label[1];\n    final Runnable[] refreshRef = new Runnable[1];\n    final boolean[] splitAdjustMode = new boolean[] { false };\n\n    Table<String> table = new Table<String>(\"State\", \"Id\", \"Version\") {\n      @Override public Interactable.Result handleKeyStroke(KeyStroke keyStroke) {\n        if (splitAdjustMode[0]) {\n          if (keyStroke.getKeyType() == KeyType.ArrowUp) {\n            splitRatio[0] = Math.max(0.3, splitRatio[0] - 0.05);\n            saveState(filterText[0], sortKey[0], sortAsc[0], splitRatio[0]);\n            recomputeSizes(window.getTextGUI().getScreen(), this, detailsRef[0], splitRatio);\n            try { this.invalidate(); if (detailsRef[0] != null) detailsRef[0].invalidate(); window.invalidate(); } catch (Throwable ignore) {}\n            return Interactable.Result.HANDLED;\n          } else if (keyStroke.getKeyType() == KeyType.ArrowDown) {\n            splitRatio[0] = Math.min(0.9, splitRatio[0] + 0.05);\n            saveState(filterText[0], sortKey[0], sortAsc[0], splitRatio[0]);\n            recomputeSizes(window.getTextGUI().getScreen(), this, detailsRef[0], splitRatio);\n            try { this.invalidate(); if (detailsRef[0] != null) detailsRef[0].invalidate(); window.invalidate(); } catch (Throwable ignore) {}\n            return Interactable.Result.HANDLED;\n          }\n        }\n        if (keyStroke.isShiftDown()) {\n          if (keyStroke.getKeyType() == KeyType.ArrowUp) {\n            splitRatio[0] = Math.max(0.3, splitRatio[0] - 0.05);\n            saveState(filterText[0], sortKey[0], sortAsc[0], splitRatio[0]);\n            recomputeSizes(window.getTextGUI().getScreen(), this, detailsRef[0], splitRatio);\n            return Interactable.Result.HANDLED;\n          } else if (keyStroke.getKeyType() == KeyType.ArrowDown) {\n            splitRatio[0] = Math.min(0.9, splitRatio[0] + 0.05);\n            saveState(filterText[0], sortKey[0], sortAsc[0], splitRatio[0]);\n            recomputeSizes(window.getTextGUI().getScreen(), this, detailsRef[0], splitRatio);\n            return Interactable.Result.HANDLED;\n          }\n        }\n        if (!splitAdjustMode[0] && (keyStroke.getKeyType() == KeyType.ArrowUp ||\n            keyStroke.getKeyType() == KeyType.ArrowDown ||\n            keyStroke.getKeyType() == KeyType.PageUp ||\n            keyStroke.getKeyType() == KeyType.PageDown ||\n            keyStroke.getKeyType() == KeyType.Home ||\n            keyStroke.getKeyType() == KeyType.End)) {\n          Interactable.Result r = super.handleKeyStroke(keyStroke);\n          Item it = findItemByRow(all, this, getSelectedRow());\n          if (it != null && detailsRef[0] != null) {\n            detailsRef[0].setText(describe(it, polRef[0]));\n            detailsRef[0].setForegroundColor(it.privileged ? TextColor.ANSI.YELLOW : TextColor.ANSI.DEFAULT);\n          }\n          return r;\n        }\n        if (keyStroke.getKeyType() == KeyType.Character) {\n          char c = keyStroke.getCharacter();\n          if (c == ' ' || c == 'c' || c == 'C') {\n            Item it = findItemByRow(all, this, getSelectedRow());\n            if (it != null) {\n              try {\n                if (c == ' ') {\n                  if (polRef[0].isAllowed(it.id)) polRef[0].deny(it.id);\n                  else if (polRef[0].isDenied(it.id)) polRef[0].allow(it.id);\n                  else {\n                    if (!confirmAllow((WindowBasedTextGUI)window.getTextGUI(), it)) return Interactable.Result.HANDLED;\n                    polRef[0].allow(it.id);\n                  }\n                } else {\n                  polRef[0].clear(it.id);\n                }\n                polRef[0].save();\n              } catch (Exception e) {\n                MessageDialog.showMessageDialog((WindowBasedTextGUI)window.getTextGUI(), \"Error\", \"Failed to update policy: \" + e.getMessage());\n              }\n              if (refreshRef[0] != null) refreshRef[0].run();\n              if (footerRef[0] != null) showToast((WindowBasedTextGUI)window.getTextGUI(), footerRef[0], scanning,\n                  () -> \"Arrows navigate • space toggle • c clear • e explain • / filter • s sort • m adjust-split • ? help • q quit\",\n                  \"Saved\", 900);\n            }\n            return Interactable.Result.HANDLED;\n          }\n        }\n        return super.handleKeyStroke(keyStroke);\n      }\n    };\n    Border tableBox = Borders.singleLine(\"Extensions\");\n    ((AbstractBorder)tableBox).setComponent(table);\n    center.addComponent(tableBox);\n\n    Label legend = new Label(\"State: ?=default, +=allowed, -=denied\");\n    center.addComponent(legend);\n\n    center.addComponent(new Separator(Direction.HORIZONTAL));\n\n    Label details = new Label(\"\");\n    Border detailsBox = Borders.singleLine(\"Details\");\n    ((AbstractBorder)detailsBox).setComponent(details);\n    center.addComponent(detailsBox);\n    detailsRef[0] = details;\n\n    root.addComponent(center, BorderLayout.Location.CENTER);\n\n    Label footer = new Label(\"Arrows navigate • space toggle • c clear • e explain • / filter • s sort • m adjust-split • ? help • q quit\");\n    footer.setForegroundColor(TextColor.ANSI.BLACK);\n    footer.setBackgroundColor(TextColor.ANSI.WHITE);\n    root.addComponent(footer, BorderLayout.Location.BOTTOM);\n    footerRef[0] = footer;\n\n    window.setComponent(root);\n\n    Runnable refresh = () -> {\n      table.getTableModel().clear();\n      String f = filterText[0].toLowerCase(Locale.ROOT);\n      Comparator<Item> cmp = comparator(sortKey[0], sortAsc[0], policy);\n      new ArrayList<>(all).stream()\n          .filter(it -> f.isEmpty() || it.id.toLowerCase(Locale.ROOT).contains(f) || it.dir.toString().toLowerCase(Locale.ROOT).contains(f))\n          .sorted(cmp)\n          .forEach(it -> table.getTableModel().addRow(stateSymbol(policy, it), it.id, it.version == null ? \"\" : it.version));\n      headerPolicy.setText(buildPolicyHeader(policy));\n      headerRepos.setText(buildReposHeader());\n      footer.setText(scanning[0]\n          ? (\"Scanning extensions… (\" + all.size() + \")  •  Press q to quit\")\n          : (splitAdjustMode[0]\n              ? \"Adjust split: Up/Down to resize • Esc to exit\"\n              : \"Arrows navigate • space toggle • c clear • e explain • / filter • s sort • m adjust-split • ? help • q quit\"));\n      int sel = table.getSelectedRow();\n      if (sel >= 0 && sel < table.getTableModel().getRowCount()) {\n        Item it = findItemByRow(all, table, sel);\n        if (it != null) {\n          details.setText(describe(it, policy));\n          details.setForegroundColor(it.privileged ? TextColor.ANSI.YELLOW : TextColor.ANSI.DEFAULT);\n        }\n      } else {\n        details.setText(\"\");\n      }\n    };\n\n    refreshRef[0] = refresh;\n\n    try {\n      DefaultTableRenderer<String> dr = (DefaultTableRenderer<String>) table.getRenderer();\n      dr.setAllowPartialColumn(false);\n      Set<Integer> expand = new HashSet<>();\n      expand.add(1);\n      dr.setExpandableColumns(expand);\n    } catch (Throwable ignored) {}\n\n    table.setTableHeaderRenderer(new TableHeaderRenderer<String>() {\n      @Override public TerminalSize getPreferredSize(Table<String> table, String label, int columnIndex) {\n        int pad = 2;\n        if (columnIndex == 0) return new TerminalSize(Math.max(3 + pad * 2, (label == null ? 0 : label.length()) + pad * 2), 1);\n        return new TerminalSize((label == null ? 0 : label.length()) + pad * 2, 1);\n      }\n      @Override public void drawHeader(Table<String> table, String label, int columnIndex, TextGUIGraphics g) {\n        String base = label == null ? \"\" : label;\n        g.setBackgroundColor(TextColor.ANSI.WHITE);\n        g.setForegroundColor(TextColor.ANSI.BLACK);\n        g.fill(' ');\n        TerminalSize sz = g.getSize();\n        int width = sz != null ? sz.getColumns() : base.length();\n        int x = Math.max(0, (width - base.length()) / 2);\n        g.enableModifiers(SGR.BOLD);\n        g.putString(x, 0, base);\n        g.disableModifiers(SGR.BOLD);\n      }\n    });\n\n    table.setTableCellRenderer(new TableCellRenderer<String>() {\n      @Override public TerminalSize getPreferredSize(Table<String> table, String cell, int column, int row) {\n        int pad = 2;\n        if (column == 0) return new TerminalSize(3 + pad * 2, 1);\n        int len = (cell == null ? 0 : cell.length()) + pad * 2;\n        return new TerminalSize(len, 1);\n      }\n      @Override public void drawCell(Table<String> table, String cell, int column, int row, TextGUIGraphics graphics) {\n        boolean isSelected = row == table.getSelectedRow();\n        if (isSelected) {\n          graphics.setBackgroundColor(TextColor.ANSI.CYAN);\n        }\n        String text = cell == null ? \"\" : cell;\n        if (column == 0) {\n          try {\n            String id = table.getTableModel().getRow(row).get(1);\n            boolean allowed = polRef[0].isAllowed(id);\n            boolean denied = polRef[0].isDenied(id);\n            String sym = allowed ? \"+\" : (denied ? \"-\" : \"?\");\n            if (DEBUG_STATE_RENDER) {\n              text = \"[\" + sym + \"]\";\n              try { System.err.println(\"[TUI-STATE] row=\" + row + \" id=\" + id + \" allowed=\" + allowed + \" denied=\" + denied + \" sym=\" + sym); } catch (Throwable ignore) {}\n            } else {\n              text = sym;\n            }\n          } catch (Exception ignored) {}\n          if (text == null || text.isEmpty() || \" \".equals(text)) text = \"?\";\n        }\n        graphics.setForegroundColor(TextColor.ANSI.BLACK);\n        TerminalSize sz = graphics.getSize();\n        graphics.fill(' ');\n        String padded = \"  \" + text + \"  \";\n        graphics.putString(0, 0, padded);\n      }\n    });\n\n    window.addWindowListener(new WindowListenerAdapter() {\n      @Override public void onUnhandledInput(Window basePane, KeyStroke keyStroke, AtomicBoolean handled) {\n        switch (keyStroke.getKeyType()) {\n          case Character: {\n            char c = keyStroke.getCharacter();\n            if (c == 'q' || c == 'Q') { saveState(filterText[0], sortKey[0], sortAsc[0], splitRatio[0]); window.close(); handled.set(true); return; }\n            if (c == '?') { showHelp(gui); handled.set(true); return; }\n            if (c == 'm' || c == 'M') {\n              if (splitAdjustMode[0]) { splitAdjustMode[0] = false; footer.setText(\"Arrows navigate • space toggle • c clear • e explain • / filter • s sort • m adjust-split • ? help • q quit\"); }\n              else { splitAdjustMode[0] = true; footer.setText(\"Adjust split: Up/Down to resize • Esc to exit\"); }\n              handled.set(true); return;\n            }\n            if (c == 'e' || c == 'E') { Item it = findItemByRow(all, table, table.getSelectedRow()); if (it != null) showPrivileges(gui, it); handled.set(true); return; }\n            if (c == '/') { String ft = new TextInputDialogBuilder().setTitle(\"Filter\").setDescription(\"Enter filter (id/path contains):\").build().showDialog(gui); if (ft != null) { filterText[0] = ft; saveState(filterText[0], sortKey[0], sortAsc[0], splitRatio[0]); refresh.run(); } handled.set(true); return; }\n            if (c == 's' || c == 'S') { SortKey chosen = chooseSort(gui, sortKey[0]); if (chosen != null) { if (chosen == sortKey[0]) sortAsc[0] = !sortAsc[0]; else { sortKey[0] = chosen; sortAsc[0] = true; } saveState(filterText[0], sortKey[0], sortAsc[0], splitRatio[0]); refresh.run(); } handled.set(true); return; }\n            if (c == 'r' || c == 'R') { scanAsync(gui, all, refresh, scanning); handled.set(true); return; }\n            break;\n          }\n          case Escape: {\n            if (splitAdjustMode[0]) { splitAdjustMode[0] = false; footer.setText(\"Arrows navigate • space toggle • c clear • e explain • / filter • s sort • m adjust-split • ? help • q quit\"); handled.set(true); return; }\n            break;\n          }\n          case ArrowUp:\n          case ArrowDown: {\n            if (splitAdjustMode[0]) {\n              if (keyStroke.getKeyType() == KeyType.ArrowUp) splitRatio[0] = Math.max(0.3, splitRatio[0] - 0.05);\n              else splitRatio[0] = Math.min(0.9, splitRatio[0] + 0.05);\n              saveState(filterText[0], sortKey[0], sortAsc[0], splitRatio[0]);\n              recomputeSizes(window.getTextGUI().getScreen(), table, details, splitRatio);\n              try { table.invalidate(); details.invalidate(); window.invalidate(); } catch (Throwable ignore) {}\n              handled.set(true); return;\n            }\n            break;\n          }\n          default: break;\n        }\n      }\n      @Override public void onResized(Window window, TerminalSize oldSize, TerminalSize newSize) {\n        recomputeSizes(window.getTextGUI().getScreen(), table, details, splitRatio);\n      }\n    });\n\n    recomputeSizes(screen, table, details, splitRatio);\n    scanAsync(gui, all, refresh, scanning);\n    window.setComponent(root);\n    gui.addWindowAndWait(window);\n    screen.stopScreen();\n  }\n\n  private static String stateSymbol(PolicyFileLite policy, Item it) {\n    if (policy.isAllowed(it.id)) return \"+\";\n    if (policy.isDenied(it.id)) return \"-\";\n    return \"?\";\n  }\n\n  private static Comparator<Item> comparator(SortKey k, boolean asc, PolicyFileLite policy) {\n    Comparator<Item> c;\n    switch (k) {\n      case STATE: c = Comparator.comparing((Item i) -> stateOrder(policy, i)); break;\n      case VERSION: c = Comparator.comparing(i -> i.version == null ? \"\" : i.version, String::compareToIgnoreCase); break;\n      case PATH: c = Comparator.comparing(i -> i.dir.toString(), String::compareToIgnoreCase); break;\n      case ID:\n      default: c = Comparator.comparing(i -> i.id, String::compareToIgnoreCase); break;\n    }\n    return asc ? c : c.reversed();\n  }\n\n  private static int stateOrder(PolicyFileLite policy, Item it) {\n    if (policy.isAllowed(it.id)) return 0;\n    if (policy.isDenied(it.id)) return 2;\n    return 1;\n  }\n\n  private static SortKey parseSortKey(String key) {\n    if (key == null) return SortKey.ID;\n    try { return SortKey.valueOf(key.toUpperCase(Locale.ROOT)); } catch (IllegalArgumentException ex) { return SortKey.ID; }\n  }\n\n  private static double clampRatio(double r) {\n    if (Double.isNaN(r) || Double.isInfinite(r)) return 0.65d;\n    if (r < 0.3d) return 0.3d;\n    if (r > 0.9d) return 0.9d;\n    return r;\n  }\n\n  private static void saveState(String filter, SortKey sortKey, boolean sortAsc, double ratio) {\n    TuiState s = new TuiState();\n    s.filter = filter == null ? \"\" : filter;\n    s.sortKey = sortKey == null ? \"ID\" : sortKey.name();\n    s.sortAsc = sortAsc;\n    s.splitRatio = clampRatio(ratio);\n    TuiState.save(s);\n  }\n\n  private static SortKey chooseSort(MultiWindowTextGUI gui, SortKey current) {\n    List<SortKey> opts = Arrays.asList(SortKey.STATE, SortKey.ID, SortKey.VERSION, SortKey.PATH);\n    return new ListSelectDialogBuilder<SortKey>()\n        .setTitle(\"Sort\")\n        .setDescription(\"Sort by (repeat to toggle asc/desc):\")\n        .addListItems(opts.toArray(new SortKey[0]))\n        .build()\n        .showDialog(gui);\n  }\n\n  private static void showHelp(MultiWindowTextGUI gui) {\n    MessageDialog.showMessageDialog(gui, \"Help\",\n        \"Keys:\\n\" +\n        \"  Arrows/PageUp/PageDown/Home/End: navigate (details update automatically)\\n\" +\n        \"  space: Toggle state in list (+/-/?)\\n\" +\n        \"  c: Clear to default (removes from allow/deny)\\n\" +\n        \"  e: Explain privileges (dialog with risk descriptions)\\n\" +\n        \"  /: Filter   s: Sort    m: Adjust split (then Up/Down, Esc to exit)\\n\" +\n        \"\\n\" +\n        \"Details panel:\\n\" +\n        \"  Shows full-word state: default / allowed / denied\\n\" +\n        \"  ?: Help     q: Quit\\n\");\n  }\n\n  private static boolean confirmAllow(WindowBasedTextGUI gui, Item it) {\n    StringBuilder sb = new StringBuilder();\n    sb.append(\"Allow extension '\" + it.id + \"'?\");\n    List<String> names = it.requiredPerms;\n    if (names != null && !names.isEmpty()) {\n      sb.append(\"\\n\\nRequests permissions:\\n\");\n      for (String n : names) {\n        String up = n.trim().toUpperCase(Locale.ROOT);\n        String desc;\n        try {\n          Permission p = Permission.valueOf(up);\n          desc = p.getRiskDescription();\n        } catch (IllegalArgumentException ex) {\n          desc = \"(unknown)\";\n        }\n        sb.append(\"  - \").append(up).append(\": \").append(desc).append('\\n');\n      }\n    } else {\n      sb.append(\"\\n\\nThis extension does not declare specific permissions.\");\n    }\n    MessageDialogButton res = MessageDialog.showMessageDialog(gui, \"Confirm Allow\", sb.toString(), MessageDialogButton.Yes, MessageDialogButton.No);\n    return res == MessageDialogButton.Yes;\n  }\n\n  private static void showToast(WindowBasedTextGUI gui, Label footer, boolean[] scanning, Supplier<String> base, String text, int millis) {\n    String old = footer.getText();\n    footer.setText(text);\n    new Thread(() -> {\n      try { Thread.sleep(millis); } catch (InterruptedException ignored) {}\n      gui.getGUIThread().invokeLater(() -> footer.setText(scanning[0] ? (\"Scanning extensions…  •  Press q to quit\") : base.get()));\n    }, \"btracex-toast\").start();\n  }\n\n  private static void showPrivileges(MultiWindowTextGUI gui, Item it) {\n    StringBuilder sb = new StringBuilder();\n    sb.append(\"Extension: \").append(it.id).append('\\n');\n    List<String> names = it.requiredPerms;\n    if (names != null && !names.isEmpty()) {\n      sb.append(\"\\nRequested permissions:\\n\");\n      for (String n : names) {\n        String up = n.trim().toUpperCase(Locale.ROOT);\n        String desc;\n        try {\n          Permission p = Permission.valueOf(up);\n          desc = p.getRiskDescription();\n        } catch (IllegalArgumentException ex) {\n          desc = \"(unknown)\";\n        }\n        sb.append(\"  - \").append(up).append(\": \").append(desc).append('\\n');\n      }\n    } else {\n      sb.append(\"\\nNo explicit permissions declared by this extension.\");\n    }\n    MessageDialog.showMessageDialog(gui, \"Privileges\", sb.toString(), MessageDialogButton.OK);\n  }\n\n  private static String describe(Item it, PolicyFileLite policy) {\n    String state = policy.isAllowed(it.id) ? \"allowed\" : (policy.isDenied(it.id) ? \"denied\" : \"default\");\n    StringBuilder sb = new StringBuilder();\n    sb.append(\"Extension: \").append(it.id)\n      .append(\"\\nVersion  : \").append(it.version == null ? \"\" : it.version)\n      .append(\"\\nPrivileged: \").append(it.privileged)\n      .append(\"\\nState    : \").append(state)\n      .append(\"\\nPath     : \").append(it.dir);\n    if (it.requiredPerms != null && !it.requiredPerms.isEmpty()) {\n      sb.append(\"\\nRequires : \");\n      for (int i = 0; i < it.requiredPerms.size(); i++) { if (i > 0) sb.append(','); sb.append(it.requiredPerms.get(i)); }\n    }\n    return sb.toString();\n  }\n\n  private static Item findItemByRow(List<Item> all, Table<String> table, int row) {\n    if (row < 0 || row >= table.getTableModel().getRowCount()) return null;\n    String id = table.getTableModel().getRow(row).get(1);\n    for (Item it : all) if (it.id.equals(id)) return it; return null;\n  }\n\n  private static void recomputeSizes(Screen screen, Table<String> table, Label details, double[] splitRatio) {\n    TerminalSize ts = screen.getTerminalSize();\n    int totalCols = Math.max(80, ts.getColumns());\n    int totalRows = Math.max(24, ts.getRows());\n    int headerFooter = 2;\n    int centerRows = Math.max(10, totalRows - headerFooter);\n    int reserved = 2;\n    int tableRows = Math.max(6, (int)Math.round(centerRows * splitRatio[0]) - reserved);\n    int detailsRows = Math.max(4, centerRows - tableRows - reserved);\n    table.setPreferredSize(new TerminalSize(totalCols, tableRows));\n    details.setPreferredSize(new TerminalSize(totalCols, detailsRows));\n  }\n\n  private static String buildPolicyHeader(PolicyFileLite policy) { return \"Policy: \" + String.valueOf(policy.getTarget()); }\n  private static String buildReposHeader() {\n    StringBuilder sb = new StringBuilder(); sb.append(\"Repos: \");\n    List<Path> roots = RepoScannerLite.roots(); boolean first = true;\n    for (Path r : roots) { if (r == null || !Files.isDirectory(r)) continue; if (!first) sb.append(\", \"); sb.append(r.toString()); first = false; }\n    if (first) sb.append(\"(none)\"); return sb.toString();\n  }\n\n  private static void scanAsync(MultiWindowTextGUI gui, List<Item> all, Runnable refresh, boolean[] scanning) {\n    if (scanning[0]) return; scanning[0] = true; all.clear(); refresh.run();\n    new Thread(() -> { try { for (Path root : RepoScannerLite.roots()) { if (root == null || !Files.isDirectory(root)) continue; try (Stream<Path> s = Files.list(root)) { for (Path p : (Iterable<Path>) s::iterator) { if (!Files.isDirectory(p)) continue; try { ExtensionInspectorLite.Report r = ExtensionInspectorLite.inspectDirectory(p); synchronized (all) { all.add(new Item(r.id, r.version, r.privileged, p, r.requiredPermNames)); } gui.getGUIThread().invokeLater(refresh); } catch (Exception ignored) {} } } catch (Exception ignored) {} } } finally { scanning[0] = false; gui.getGUIThread().invokeLater(refresh); } }, \"btracex-scan\").start();\n  }\n\n  private static final class Item {\n    final String id; final String version; final boolean privileged; final Path dir; final List<String> requiredPerms;\n    Item(String id, String version, boolean privileged, Path dir) { this(id, version, privileged, dir, Collections.emptyList()); }\n    Item(String id, String version, boolean privileged, Path dir, List<String> requiredPerms) { this.id = id; this.version = version; this.privileged = privileged; this.dir = dir; this.requiredPerms = requiredPerms; }\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/tui/ExtensionInspectorLite.java",
    "content": "package org.openjdk.btrace.extcli.tui;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.file.*;\nimport java.util.*;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\nimport org.openjdk.btrace.core.extensions.Extension;\nimport org.openjdk.btrace.core.extensions.ExtensionMeta;\nimport org.openjdk.btrace.core.extensions.Permission;\n\nfinal class ExtensionInspectorLite {\n  static class Report {\n    final String id;\n    final String version;\n    final boolean privileged;\n    final Set<String> services;\n    final java.util.List<String> requiredPermNames;\n\n    Report(String id, String version, boolean privileged, Set<String> services, java.util.List<String> requiredPermNames) {\n      this.id = id; this.version = version; this.privileged = privileged; this.services = services; this.requiredPermNames = requiredPermNames != null ? requiredPermNames : java.util.Collections.emptyList();\n    }\n  }\n\n  static Report inspectDirectory(Path dir) throws IOException {\n    Path api = findFirstDeep(dir, \"-api.jar\");\n    Path impl = findFirstDeep(dir, \"-impl.jar\");\n    if (api == null || impl == null) throw new IOException(\"Missing api/impl jars under \" + dir);\n\n    String id = readIdFromJar(api);\n    if (id == null || id.isEmpty()) {\n      String n = dir.getFileName() != null ? dir.getFileName().toString() : dir.toString();\n      id = stripVersionFromName(n);\n    }\n    String version = readVersionFromJar(api);\n    if (version == null || version.isEmpty()) {\n      String n = api.getFileName() != null ? api.getFileName().toString() : api.toString();\n      version = n.replaceFirst(\"^[^-]+-\", \"\").replaceFirst(\"-api\\\\.jar$\", \"\");\n    }\n    List<String> perms = new ArrayList<>();\n    perms.addAll(readPermissionsFromManifestOrProps(api));\n    perms.addAll(readPermissionsFromManifestOrProps(impl));\n    LinkedHashSet<String> ded = new LinkedHashSet<>();\n    for (String n : perms) { String t = n.trim(); if (!t.isEmpty()) ded.add(t); }\n    boolean privileged = computePrivileged(api, impl);\n    Set<String> services = readServices(impl);\n    return new Report(id, version, privileged, services, new ArrayList<>(ded));\n  }\n\n  private static String stripVersionFromName(String name) {\n    if (name == null || name.isEmpty()) return name;\n    int idx = name.lastIndexOf('-');\n    if (idx > 0 && idx + 1 < name.length() && Character.isDigit(name.charAt(idx + 1))) {\n      return name.substring(0, idx);\n    }\n    return name;\n  }\n\n  private static Path findFirstDeep(Path root, String suffix) throws IOException {\n    try (Stream<Path> s = Files.walk(root)) {\n      Optional<Path> p = s.filter(pth -> pth.getFileName() != null && pth.getFileName().toString().endsWith(suffix)).findFirst();\n      return p.orElse(null);\n    }\n  }\n\n  private static String readVersionFromJar(Path apiJar) {\n    try (JarFile jf = new JarFile(apiJar.toFile())) {\n      Manifest mf = jf.getManifest();\n      if (mf != null) {\n        String v = mf.getMainAttributes().getValue(\"Implementation-Version\");\n        if (v != null) return v;\n        v = mf.getMainAttributes().getValue(\"BTrace-Extension-Version\");\n        if (v != null) return v;\n      }\n    } catch (IOException ignored) {}\n    return \"\";\n  }\n\n  private static String readIdFromJar(Path jarPath) {\n    try (JarFile jf = new JarFile(jarPath.toFile())) {\n      Manifest mf = jf.getManifest();\n      if (mf != null) {\n        String id = mf.getMainAttributes().getValue(\"BTrace-Extension-Id\");\n        if (id != null && !id.isEmpty()) return id;\n      }\n      JarEntry props = jf.getJarEntry(\"META-INF/btrace-extension.properties\");\n      if (props != null) {\n        Properties p = new Properties();\n        try (InputStream is = jf.getInputStream(props)) { p.load(is); }\n        String id = p.getProperty(\"extension.id\", \"\");\n        if (!id.isEmpty()) return id;\n      }\n    } catch (IOException ignored) {}\n    return \"\";\n  }\n\n  private static Set<String> readServices(Path implJar) {\n    Set<String> services = new HashSet<>();\n    try (JarFile jf = new JarFile(implJar.toFile())) {\n      Enumeration<JarEntry> en = jf.entries();\n      while (en.hasMoreElements()) {\n        JarEntry e = en.nextElement();\n        if (e.getName().startsWith(\"META-INF/services/\") && !e.isDirectory()) {\n          services.add(e.getName().substring(\"META-INF/services/\".length()));\n        }\n      }\n    } catch (IOException ignored) {}\n    return services;\n  }\n\n  private static boolean computePrivileged(Path apiJar, Path implJar) {\n    List<String> names = new ArrayList<>();\n    names.addAll(readPermissionsFromManifestOrProps(apiJar));\n    names.addAll(readPermissionsFromManifestOrProps(implJar));\n    for (String n : names) {\n      String u = n.trim().toUpperCase();\n      if (u.equals(\"FILE_WRITE\") || u.equals(\"NETWORK\") || u.equals(\"THREADS\") || u.equals(\"NATIVE\") || u.equals(\"EXEC\") || u.equals(\"REFLECTION\") || u.equals(\"CLASSLOADER\") || u.equals(\"UNLIMITED_MEMORY\")) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private static List<String> readPermissionsFromManifestOrProps(Path jarPath) {\n    List<String> perms = new ArrayList<>();\n    try (JarFile jf = new JarFile(jarPath.toFile())) {\n      Manifest mf = jf.getManifest();\n      if (mf != null) {\n        String v = mf.getMainAttributes().getValue(\"BTrace-Extension-Permissions\");\n        if (v != null && !v.trim().isEmpty()) {\n          for (String part : v.split(\",\")) { String s = part.trim(); if (!s.isEmpty()) perms.add(s); }\n          return perms;\n        }\n      }\n      JarEntry e = jf.getJarEntry(\"META-INF/btrace-extension.properties\");\n      if (e != null) {\n        Properties p = new Properties();\n        try (InputStream is = jf.getInputStream(e)) { p.load(is); }\n        String v = p.getProperty(\"requires.permissions\", \"\");\n        if (!v.isEmpty()) { for (String part : v.split(\",\")) { String s = part.trim(); if (!s.isEmpty()) perms.add(s); } }\n      }\n    } catch (IOException ignored) {}\n    return perms;\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/tui/PolicyFileLite.java",
    "content": "package org.openjdk.btrace.extcli.tui;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\nimport java.nio.file.StandardCopyOption;\n\nfinal class PolicyFileLite {\n  private final Properties props = new Properties();\n  private final Path target;\n\n  static PolicyFileLite homeDefault() throws IOException {\n    Path t = Path.of(System.getProperty(\"user.home\"), \".btrace\", \"permissions.properties\");\n    return new PolicyFileLite(t);\n  }\n\n  PolicyFileLite(Path target) throws IOException {\n    this.target = target;\n    loadIfExists();\n  }\n\n  Path getTarget() { return target; }\n\n  boolean isAllowed(String id) { return list(\"allowExtensions\").contains(id); }\n  boolean isDenied(String id) { return list(\"denyExtensions\").contains(id); }\n\n  void allow(String id) { alterLists(id, true); }\n  void deny(String id) { alterLists(id, false); }\n  void clear(String id) {\n    List<String> al = list(\"allowExtensions\");\n    if (al.remove(id)) props.setProperty(\"allowExtensions\", String.join(\",\", al));\n    List<String> dl = list(\"denyExtensions\");\n    if (dl.remove(id)) props.setProperty(\"denyExtensions\", String.join(\",\", dl));\n  }\n\n  private void alterLists(String id, boolean allow) {\n    List<String> al = list(\"allowExtensions\");\n    List<String> dl = list(\"denyExtensions\");\n    if (allow) {\n      if (!al.contains(id)) al.add(id);\n      dl.remove(id);\n    } else {\n      if (!dl.contains(id)) dl.add(id);\n      al.remove(id);\n    }\n    props.setProperty(\"allowExtensions\", String.join(\",\", al));\n    props.setProperty(\"denyExtensions\", String.join(\",\", dl));\n  }\n\n  private List<String> list(String key) {\n    List<String> res = new ArrayList<>();\n    String csv = props.getProperty(key, \"\");\n    if (csv == null || csv.trim().isEmpty()) return res;\n    for (String s : csv.split(\",\")) { String t = s.trim(); if (!t.isEmpty()) res.add(t); }\n    return res;\n  }\n\n  void save() throws IOException {\n    Files.createDirectories(target.getParent());\n    Path tmp = target.resolveSibling(target.getFileName() + \".tmp\");\n    try (OutputStream os = Files.newOutputStream(tmp)) { props.store(os, \"BTrace permissions policy\"); }\n    Files.move(tmp, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);\n  }\n\n  String getAllowPrivileged() { return props.getProperty(\"allowPrivileged\", \"false\"); }\n\n  void toggleAllowPrivileged() {\n    String cur = props.getProperty(\"allowPrivileged\", \"false\");\n    boolean b = Boolean.parseBoolean(cur);\n    props.setProperty(\"allowPrivileged\", Boolean.toString(!b));\n  }\n\n  private void loadIfExists() throws IOException {\n    if (Files.exists(target)) try (InputStream is = Files.newInputStream(target)) { props.load(is); }\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/tui/RepoScannerLite.java",
    "content": "package org.openjdk.btrace.extcli.tui;\n\nimport java.io.File;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.List;\n\nfinal class RepoScannerLite {\n  static List<Path> roots() {\n    List<Path> roots = new ArrayList<>();\n    String home = System.getenv(\"BTRACE_HOME\");\n    if (home != null && !home.isEmpty()) roots.add(Path.of(home, \"extensions\"));\n    roots.add(Path.of(System.getProperty(\"user.home\"), \".btrace\", \"extensions\"));\n    String extra = System.getenv(\"BTRACE_EXT_PATH\");\n    if (extra != null && !extra.isEmpty()) {\n      for (String p : extra.split(File.pathSeparator)) roots.add(Path.of(p));\n    }\n    return roots;\n  }\n}\n\n"
  },
  {
    "path": "btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/tui/TuiState.java",
    "content": "package org.openjdk.btrace.extcli.tui;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Properties;\n\nfinal class TuiState {\n  String filter = \"\";\n  String sortKey = \"ID\";\n  boolean sortAsc = true;\n  double splitRatio = 0.65d;\n\n  static TuiState load() {\n    TuiState s = new TuiState();\n    try {\n      Path dir = Path.of(System.getProperty(\"user.home\"), \".btrace\");\n      Path f = dir.resolve(\"tui-state.properties\");\n      if (Files.exists(f)) {\n        Properties p = new Properties();\n        try (InputStream is = Files.newInputStream(f)) { p.load(is); }\n        s.filter = p.getProperty(\"filter\", s.filter);\n        s.sortKey = p.getProperty(\"sortKey\", s.sortKey);\n        s.sortAsc = Boolean.parseBoolean(p.getProperty(\"sortAsc\", Boolean.toString(s.sortAsc)));\n        try { s.splitRatio = Double.parseDouble(p.getProperty(\"splitRatio\", Double.toString(s.splitRatio))); } catch (NumberFormatException ignored) {}\n      }\n    } catch (IOException ignored) { }\n    return s;\n  }\n\n  static void save(TuiState s) {\n    try {\n      Path dir = Path.of(System.getProperty(\"user.home\"), \".btrace\");\n      Files.createDirectories(dir);\n      Path f = dir.resolve(\"tui-state.properties\");\n      Properties p = new Properties();\n      p.setProperty(\"filter\", s.filter != null ? s.filter : \"\");\n      p.setProperty(\"sortKey\", s.sortKey != null ? s.sortKey : \"ID\");\n      p.setProperty(\"sortAsc\", Boolean.toString(s.sortAsc));\n      p.setProperty(\"splitRatio\", Double.toString(s.splitRatio));\n      try (OutputStream os = Files.newOutputStream(f)) { p.store(os, \"BTrace TUI state\"); }\n    } catch (IOException ignored) { }\n  }\n}\n\n"
  },
  {
    "path": "btrace-ext-cli/src/test/java/org/openjdk/btrace/extcli/ExtensionInspectorTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extcli;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nclass ExtensionInspectorTest {\n\n  @TempDir Path tempDir;\n\n  @Test\n  void inspectValidDirectory() throws IOException {\n    Path extDir = tempDir.resolve(\"test-extension\");\n    TestExtensionBuilder.createExtensionDirectory(\"test-ext\", \"1.0.0\", extDir, false);\n\n    ExtensionReport report = ExtensionInspector.inspect(extDir);\n\n    assertTrue(report.ok, \"Extension should be valid\");\n    assertEquals(\"test-ext\", report.id);\n    assertEquals(\"1.0.0\", report.version);\n    assertFalse(report.privileged, \"Extension should not be privileged\");\n  }\n\n  @Test\n  void inspectValidZip() throws IOException {\n    Path zipFile = tempDir.resolve(\"test-extension.zip\");\n    TestExtensionBuilder.createExtensionZip(\"test-ext\", \"2.0.0\", zipFile, false);\n\n    ExtensionReport report = ExtensionInspector.inspect(zipFile);\n\n    assertTrue(report.ok, \"Extension ZIP should be valid\");\n    assertEquals(\"test-ext\", report.id);\n    assertEquals(\"2.0.0\", report.version);\n  }\n\n  @Test\n  void detectMissingApiJar() throws IOException {\n    Path extDir = tempDir.resolve(\"incomplete-extension\");\n    Files.createDirectories(extDir);\n    // Only create impl jar, no api jar\n    Path implJar = extDir.resolve(\"test-1.0.0-impl.jar\");\n    TestExtensionBuilder.createImplJar(\"test\", implJar);\n\n    ExtensionReport report = ExtensionInspector.inspect(extDir);\n\n    assertFalse(report.ok, \"Extension should be invalid without API JAR\");\n    assertTrue(report.message.contains(\"Missing api/impl jars\"));\n  }\n\n  @Test\n  void detectMissingImplJar() throws IOException {\n    Path extDir = tempDir.resolve(\"incomplete-extension\");\n    Files.createDirectories(extDir);\n    // Only create api jar, no impl jar\n    Path apiJar = extDir.resolve(\"test-1.0.0-api.jar\");\n    TestExtensionBuilder.createApiJar(\"test\", \"1.0.0\", apiJar, false);\n\n    ExtensionReport report = ExtensionInspector.inspect(extDir);\n\n    assertFalse(report.ok, \"Extension should be invalid without implementation JAR\");\n    assertTrue(report.message.contains(\"Missing api/impl jars\"));\n  }\n\n  @Test\n  void inspectExtensionWithPermissions() throws IOException {\n    Path extDir = tempDir.resolve(\"permissions-extension\");\n    TestExtensionBuilder.createExtensionDirectory(\"perm-ext\", \"1.0.0\", extDir, true);\n\n    ExtensionReport report = ExtensionInspector.inspect(extDir);\n\n    assertTrue(report.ok, \"Extension with permissions should be valid\");\n    // Note: Privileged detection requires actual ExtensionMeta from compiled classes,\n    // which is beyond the scope of simple unit testing with programmatic JAR creation\n  }\n\n  @Test\n  void extractManifestId() throws IOException {\n    Path extDir = tempDir.resolve(\"manifest-id-test\");\n    TestExtensionBuilder.createExtensionDirectory(\"manifest-ext\", \"1.5.0\", extDir, false);\n\n    ExtensionReport report = ExtensionInspector.inspect(extDir);\n\n    assertEquals(\"manifest-ext\", report.id, \"Should extract ID from manifest\");\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/test/java/org/openjdk/btrace/extcli/ExtensionListerTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extcli;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nclass ExtensionListerTest {\n\n  @TempDir Path tempDir;\n\n  private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();\n  private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();\n  private final PrintStream originalOut = System.out;\n  private final PrintStream originalErr = System.err;\n  private String originalBtraceHome;\n\n  @BeforeEach\n  void setUpStreams() {\n    System.setOut(new PrintStream(outContent));\n    System.setErr(new PrintStream(errContent));\n    originalBtraceHome = System.getenv(\"BTRACE_HOME\");\n  }\n\n  @AfterEach\n  void restoreStreams() {\n    System.setOut(originalOut);\n    System.setErr(originalErr);\n  }\n\n  @Test\n  void listFromBtraceHome() throws IOException {\n    // Create extensions directory with one extension\n    Path extensionsDir = tempDir.resolve(\"extensions\");\n    Files.createDirectories(extensionsDir);\n    Path ext1 = extensionsDir.resolve(\"ext1\");\n    TestExtensionBuilder.createExtensionDirectory(\"ext1\", \"1.0.0\", ext1, false);\n\n    // Set BTRACE_HOME temporarily using reflection (since we can't actually change env vars)\n    // Instead, we'll just verify the lister doesn't crash with empty dirs\n    ExtensionLister.list(false);\n\n    // Should not crash, output may be empty since BTRACE_HOME is not set\n    String output = outContent.toString();\n    assertNotNull(output);\n  }\n\n  @Test\n  void listWithJsonFormat() throws IOException {\n    ExtensionLister.list(true);\n\n    String output = outContent.toString();\n    // Should output valid JSON (starts with [ and ends with ])\n    assertTrue(\n        output.trim().startsWith(\"[\") && output.trim().endsWith(\"]\"),\n        \"JSON output should be an array\");\n  }\n\n  @Test\n  void listHandlesEmptyDirectories() throws IOException {\n    // Create empty extensions directory\n    Path extensionsDir = tempDir.resolve(\"extensions\");\n    Files.createDirectories(extensionsDir);\n\n    // Should handle gracefully without errors\n    assertDoesNotThrow(() -> ExtensionLister.list(false));\n  }\n\n  @Test\n  void listOutputsExtensionInfo() throws IOException {\n    // Since we can't easily set environment variables, we verify the method\n    // completes without throwing exceptions\n    assertDoesNotThrow(() -> ExtensionLister.list(false));\n    assertDoesNotThrow(() -> ExtensionLister.list(true));\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/test/java/org/openjdk/btrace/extcli/InstallerTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extcli;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.PrintStream;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.List;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nclass InstallerTest {\n\n  @TempDir Path tempDir;\n\n  private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();\n  private final PrintStream originalOut = System.out;\n\n  @BeforeEach\n  void setUpStreams() {\n    System.setOut(new PrintStream(outContent));\n  }\n\n  @AfterEach\n  void restoreStreams() {\n    System.setOut(originalOut);\n  }\n\n  @Test\n  void dryRunFromLocalZip() throws Exception {\n    Path zipFile = tempDir.resolve(\"test-ext.zip\");\n    TestExtensionBuilder.createExtensionZip(\"test-ext\", \"1.0.0\", zipFile, false);\n\n    Installer.install(zipFile.toString(), Collections.emptyList(), null, true);\n\n    String output = outContent.toString();\n    assertTrue(output.contains(\"[DRY-RUN]\"), \"Should indicate dry-run mode\");\n    assertTrue(output.contains(\"Would install\"), \"Should show install action\");\n  }\n\n  @Test\n  void dryRunFromUrl() throws Exception {\n    Installer.install(\n        \"https://example.com/test-ext.zip\", Collections.emptyList(), null, true);\n\n    String output = outContent.toString();\n    assertTrue(output.contains(\"[DRY-RUN]\"), \"Should indicate dry-run mode\");\n    assertTrue(output.contains(\"Would download\"), \"Should show download action\");\n  }\n\n  @Test\n  void dryRunFromMavenGav() throws Exception {\n    List<String> repos = List.of(\"https://repo1.maven.org/maven2\");\n    Installer.install(\"org.example:test-ext:1.0.0\", repos, null, true);\n\n    String output = outContent.toString();\n    assertTrue(output.contains(\"[DRY-RUN]\"), \"Should indicate dry-run mode\");\n    assertTrue(output.contains(\"Candidate URLs\"), \"Should show candidate Maven URLs\");\n  }\n\n  @Test\n  void dryRunWithCustomId() throws Exception {\n    Path zipFile = tempDir.resolve(\"test.zip\");\n    TestExtensionBuilder.createExtensionZip(\"test-ext\", \"1.0.0\", zipFile, false);\n\n    Installer.install(zipFile.toString(), Collections.emptyList(), \"custom-id\", true);\n\n    String output = outContent.toString();\n    assertTrue(output.contains(\"[DRY-RUN]\"), \"Should indicate dry-run mode\");\n  }\n\n  @Test\n  void invalidGavCoordinateThrowsException() {\n    assertThrows(\n        IllegalArgumentException.class,\n        () -> Installer.install(\"invalid:coordinate\", Collections.emptyList(), null, true),\n        \"Should reject invalid GAV coordinate\");\n  }\n\n  @Test\n  void unrecognizedInputThrowsException() {\n    assertThrows(\n        IllegalArgumentException.class,\n        () -> Installer.install(\"not-a-valid-input\", Collections.emptyList(), null, true),\n        \"Should reject unrecognized input\");\n  }\n\n  @Test\n  void multipleReposInDryRun() throws Exception {\n    List<String> repos = List.of(\"https://repo1.example.com\", \"https://repo2.example.com\");\n    Installer.install(\"com.example:test:1.0\", repos, null, true);\n\n    String output = outContent.toString();\n    assertTrue(\n        output.contains(\"repo1.example.com\") && output.contains(\"repo2.example.com\"),\n        \"Should show all candidate repositories\");\n  }\n\n  @Test\n  void derivesIdFromZipFilename() throws Exception {\n    Path zipFile = tempDir.resolve(\"my-extension-1.2.3.zip\");\n    TestExtensionBuilder.createExtensionZip(\"my-ext\", \"1.2.3\", zipFile, false);\n\n    Installer.install(zipFile.toString(), Collections.emptyList(), null, true);\n\n    String output = outContent.toString();\n    assertTrue(output.contains(\"[DRY-RUN]\"), \"Should complete dry-run\");\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/test/java/org/openjdk/btrace/extcli/MainTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extcli;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.nio.file.Path;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nclass MainTest {\n\n  @TempDir Path tempDir;\n\n  private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();\n  private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();\n  private final PrintStream originalOut = System.out;\n  private final PrintStream originalErr = System.err;\n\n  @BeforeEach\n  void setUpStreams() {\n    System.setOut(new PrintStream(outContent));\n    System.setErr(new PrintStream(errContent));\n  }\n\n  @AfterEach\n  void restoreStreams() {\n    System.setOut(originalOut);\n    System.setErr(originalErr);\n  }\n\n  @Test\n  void showsHelpWithNoArgs() throws Exception {\n    Main.main(new String[] {});\n\n    String output = outContent.toString();\n    assertTrue(output.contains(\"Usage\") || output.contains(\"usage\"), \"Should show usage\");\n  }\n\n  @Test\n  void showsHelpWithHelpFlag() throws Exception {\n    Main.main(new String[] {\"--help\"});\n\n    String output = outContent.toString();\n    assertTrue(output.contains(\"Usage\") || output.contains(\"usage\"), \"Should show usage\");\n  }\n\n  @Test\n  void inspectCommandWithValidExtension() throws Exception {\n    Path extDir = tempDir.resolve(\"test-ext\");\n    TestExtensionBuilder.createExtensionDirectory(\"test-ext\", \"1.0.0\", extDir, false);\n\n    Main.main(new String[] {\"inspect\", extDir.toString()});\n\n    String output = outContent.toString();\n    assertTrue(output.contains(\"test-ext\"), \"Should display extension ID\");\n  }\n\n  @Test\n  void inspectCommandWithJsonFlag() throws Exception {\n    Path extDir = tempDir.resolve(\"test-ext\");\n    TestExtensionBuilder.createExtensionDirectory(\"test-ext\", \"1.0.0\", extDir, false);\n\n    Main.main(new String[] {\"inspect\", extDir.toString(), \"--json\"});\n\n    String output = outContent.toString();\n    assertTrue(output.contains(\"{\") && output.contains(\"}\"), \"Should output JSON\");\n    assertTrue(output.contains(\"\\\"id\\\"\"), \"JSON should contain id field\");\n  }\n\n  @Test\n  void listCommandExecutes() throws Exception {\n    Main.main(new String[] {\"list\"});\n\n    // Should execute without throwing exception\n    String output = outContent.toString();\n    assertNotNull(output);\n  }\n\n  @Test\n  void unknownCommandShowsError() throws Exception {\n    Main.main(new String[] {\"invalid-command\"});\n\n    String error = errContent.toString();\n    assertTrue(error.contains(\"Unknown command\"), \"Should show unknown command error\");\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/test/java/org/openjdk/btrace/extcli/PolicyFileTest.java",
    "content": "package org.openjdk.btrace.extcli;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport java.io.IOException;\nimport java.nio.file.Path;\nimport java.util.List;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass PolicyFileTest {\n  @TempDir\n  Path tempDir;\n\n  @Test\n  void saveAndReloadPolicy() throws IOException {\n    Path policy = tempDir.resolve(\"permissions.properties\");\n    PolicyFile pf = PolicyFile.fromArgs(new String[] {\"--policy-file\", policy.toString()});\n    pf.updateFromArgs(new String[] {\"--allowExtensions\", \"a,b\", \"--denyExtensions\", \"c\", \"--allowPrivileged\", \"true\"});\n    pf.save();\n\n    PolicyFile reloaded = PolicyFile.fromArgs(new String[] {\"--policy-file\", policy.toString()});\n    assertEquals(List.of(\"a\", \"b\"), reloaded.getAllowList());\n    assertEquals(List.of(\"c\"), reloaded.getDenyList());\n    assertTrue(reloaded.describe(true).contains(\"\\\"allowPrivileged\\\":\\\"true\\\"\"));\n  }\n\n  @Test\n  void allowDenyAndClearUpdateLists() throws IOException {\n    Path policy = tempDir.resolve(\"policy.properties\");\n    PolicyFile pf = PolicyFile.fromArgs(new String[] {\"--policy-file\", policy.toString()});\n\n    pf.allow(\"ext-a\");\n    assertEquals(List.of(\"ext-a\"), pf.getAllowList());\n    assertEquals(List.of(), pf.getDenyList());\n\n    pf.deny(\"ext-a\");\n    assertEquals(List.of(), pf.getAllowList());\n    assertEquals(List.of(\"ext-a\"), pf.getDenyList());\n\n    pf.clear(\"ext-a\");\n    assertEquals(List.of(), pf.getAllowList());\n    assertEquals(List.of(), pf.getDenyList());\n  }\n\n  @Test\n  void rejectsMultipleTargets() {\n    assertThrows(\n        IllegalArgumentException.class,\n        () -> PolicyFile.fromArgs(new String[] {\"--policy-file\", \"a\", \"--home\"}));\n  }\n\n  @Test\n  void classpathTargetResolvesToMetaInf() throws IOException {\n    PolicyFile pf = PolicyFile.fromArgs(new String[] {\"--classpath\", tempDir.toString()});\n    Path expected = tempDir.resolve(\"META-INF/btrace/permissions.properties\");\n    assertEquals(expected, pf.getTarget());\n  }\n}\n"
  },
  {
    "path": "btrace-ext-cli/src/test/java/org/openjdk/btrace/extcli/TestExtensionBuilder.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extcli;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Comparator;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\n/**\n * Helper class to build test extension JARs programmatically.\n */\nclass TestExtensionBuilder {\n\n  /**\n   * Creates a valid API JAR with extension metadata.\n   *\n   * @param id Extension ID\n   * @param version Extension version\n   * @param output Output file path\n   * @param privileged Whether extension requires privileged permissions\n   * @throws IOException if JAR creation fails\n   */\n  static void createApiJar(String id, String version, Path output, boolean privileged)\n      throws IOException {\n    Manifest manifest = new Manifest();\n    manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, \"1.0\");\n    manifest.getMainAttributes().putValue(\"BTrace-Extension-Id\", id);\n    manifest.getMainAttributes().putValue(\"BTrace-Extension-Version\", version);\n\n    try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(output.toFile()), manifest)) {\n      // Add META-INF/btrace/exports.index\n      jos.putNextEntry(new JarEntry(\"META-INF/btrace/\"));\n      jos.closeEntry();\n\n      jos.putNextEntry(new JarEntry(\"META-INF/btrace/exports.index\"));\n      jos.write(\"org.example.TestService\\n\".getBytes(StandardCharsets.UTF_8));\n      jos.closeEntry();\n\n      // Add permissions.properties if privileged\n      if (privileged) {\n        jos.putNextEntry(new JarEntry(\"META-INF/btrace/permissions.properties\"));\n        jos.write(\"permissions=IO,NETWORK\\n\".getBytes(StandardCharsets.UTF_8));\n        jos.closeEntry();\n      }\n    }\n  }\n\n  /**\n   * Creates a valid implementation JAR.\n   *\n   * @param id Extension ID\n   * @param output Output file path\n   * @throws IOException if JAR creation fails\n   */\n  static void createImplJar(String id, Path output) throws IOException {\n    Manifest manifest = new Manifest();\n    manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, \"1.0\");\n\n    try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(output.toFile()), manifest)) {\n      // Add META-INF/services entry\n      jos.putNextEntry(new JarEntry(\"META-INF/services/\"));\n      jos.closeEntry();\n\n      jos.putNextEntry(new JarEntry(\"META-INF/services/org.example.TestService\"));\n      jos.write(\"org.example.TestServiceImpl\\n\".getBytes(StandardCharsets.UTF_8));\n      jos.closeEntry();\n\n      // Add a dummy class file\n      jos.putNextEntry(new JarEntry(\"org/example/TestServiceImpl.class\"));\n      // Minimal valid class file (empty class)\n      byte[] classBytes = createMinimalClassFile();\n      jos.write(classBytes);\n      jos.closeEntry();\n    }\n  }\n\n  /**\n   * Creates a valid extension ZIP containing API and implementation JARs.\n   *\n   * @param id Extension ID\n   * @param version Extension version\n   * @param output Output ZIP file path\n   * @param privileged Whether extension requires privileged permissions\n   * @throws IOException if ZIP creation fails\n   */\n  static void createExtensionZip(String id, String version, Path output, boolean privileged)\n      throws IOException {\n    Path tempDir = Files.createTempDirectory(\"btrace-ext-test\");\n    try {\n      Path apiJar = tempDir.resolve(id + \"-\" + version + \"-api.jar\");\n      Path implJar = tempDir.resolve(id + \"-\" + version + \"-impl.jar\");\n\n      createApiJar(id, version, apiJar, privileged);\n      createImplJar(id, implJar);\n\n      try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(output.toFile()))) {\n        addFileToZip(zos, apiJar, apiJar.getFileName().toString());\n        addFileToZip(zos, implJar, implJar.getFileName().toString());\n      }\n    } finally {\n      // Recursively clean up temp directory and all contents\n      Files.walk(tempDir)\n          .sorted(Comparator.reverseOrder())\n          .forEach(\n              p -> {\n                try {\n                  Files.deleteIfExists(p);\n                } catch (IOException ignored) {\n                }\n              });\n    }\n  }\n\n  /**\n   * Creates an extension directory structure with API and implementation JARs.\n   *\n   * @param id Extension ID\n   * @param version Extension version\n   * @param outputDir Output directory path\n   * @param privileged Whether extension requires privileged permissions\n   * @throws IOException if creation fails\n   */\n  static void createExtensionDirectory(String id, String version, Path outputDir, boolean privileged)\n      throws IOException {\n    Files.createDirectories(outputDir);\n    Path apiJar = outputDir.resolve(id + \"-\" + version + \"-api.jar\");\n    Path implJar = outputDir.resolve(id + \"-\" + version + \"-impl.jar\");\n\n    createApiJar(id, version, apiJar, privileged);\n    createImplJar(id, implJar);\n  }\n\n  private static void addFileToZip(ZipOutputStream zos, Path file, String name)\n      throws IOException {\n    zos.putNextEntry(new ZipEntry(name));\n    Files.copy(file, zos);\n    zos.closeEntry();\n  }\n\n  /**\n   * Creates a minimal structurally valid Java class file for testing.\n   *\n   * <p>Constant pool layout:\n   *\n   * <pre>\n   *   #1 CONSTANT_Class -> #3\n   *   #2 CONSTANT_Class -> #4\n   *   #3 CONSTANT_Utf8  \"org/example/TestServiceImpl\"\n   *   #4 CONSTANT_Utf8  \"java/lang/Object\"\n   * </pre>\n   */\n  private static byte[] createMinimalClassFile() {\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    // Magic number\n    writeU4(baos, 0xCAFEBABEL);\n    // Minor version: 0, Major version: 52 (Java 8)\n    writeU2(baos, 0);\n    writeU2(baos, 52);\n    // Constant pool count: 5 (entries 1..4)\n    writeU2(baos, 5);\n    // #1 CONSTANT_Class -> #3\n    baos.write(7);\n    writeU2(baos, 3);\n    // #2 CONSTANT_Class -> #4\n    baos.write(7);\n    writeU2(baos, 4);\n    // #3 CONSTANT_Utf8 \"org/example/TestServiceImpl\"\n    byte[] thisName = \"org/example/TestServiceImpl\".getBytes(StandardCharsets.UTF_8);\n    baos.write(1);\n    writeU2(baos, thisName.length);\n    baos.write(thisName, 0, thisName.length);\n    // #4 CONSTANT_Utf8 \"java/lang/Object\"\n    byte[] superName = \"java/lang/Object\".getBytes(StandardCharsets.UTF_8);\n    baos.write(1);\n    writeU2(baos, superName.length);\n    baos.write(superName, 0, superName.length);\n    // Access flags: public\n    writeU2(baos, 0x0021);\n    // This class: #1\n    writeU2(baos, 1);\n    // Super class: #2\n    writeU2(baos, 2);\n    // Interfaces count: 0\n    writeU2(baos, 0);\n    // Fields count: 0\n    writeU2(baos, 0);\n    // Methods count: 0\n    writeU2(baos, 0);\n    // Attributes count: 0\n    writeU2(baos, 0);\n    return baos.toByteArray();\n  }\n\n  private static void writeU2(ByteArrayOutputStream baos, int value) {\n    baos.write((value >> 8) & 0xFF);\n    baos.write(value & 0xFF);\n  }\n\n  private static void writeU4(ByteArrayOutputStream baos, long value) {\n    baos.write((int) ((value >> 24) & 0xFF));\n    baos.write((int) ((value >> 16) & 0xFF));\n    baos.write((int) ((value >> 8) & 0xFF));\n    baos.write((int) (value & 0xFF));\n  }\n}\n"
  },
  {
    "path": "btrace-extension/build.gradle",
    "content": "buildscript { scriptHandler ->\n    apply from: rootProject.file('buildSrc/shared.gradle'), to: scriptHandler\n}\n\nplugins {\n    alias(libs.plugins.versioning)\n    id 'jacoco'\n}\n\ndependencies {\n    compileOnly project(':btrace-core')\n\n    implementation libs.slf4j\n    implementation libs.slf4j.simple\n\n    testImplementation project(':btrace-core')\n}\n\njacoco {\n    toolVersion = \"0.8.14\"\n}\n\njacocoTestReport {\n    dependsOn test\n    reports {\n        xml.required = true\n        html.required = true\n        csv.required = false\n    }\n\n    // Focus on v2 protocol package\n    afterEvaluate {\n        classDirectories.setFrom(files(classDirectories.files.collect {\n            fileTree(dir: it, include: [\n                '**/org/openjdk/btrace/core/comm/**/*.class'\n            ])\n        }))\n    }\n}\n\ntest {\n    finalizedBy jacocoTestReport\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/ExtensionBridge.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extension;\n\n/**\n * Bridge interface for accessing BTrace extensions from invokedynamic bootstrap methods.\n * Implemented by agent-side code to provide access to extension classes.\n */\npublic interface ExtensionBridge {\n  /**\n   * Load and return the specified extension service class.\n   *\n   * @param serviceClassName fully qualified service class name\n   * @return service class, or null if not found\n   * @throws Exception if class loading fails\n   */\n  Class<?> getExtensionClass(String serviceClassName) throws Exception;\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/ExtensionDescriptorDTO.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extension;\n\nimport org.openjdk.btrace.core.extensions.PermissionSet;\n\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\n/**\n * Descriptor for a BTrace extension loaded from an extension JAR.\n * Contains metadata about the extension including identity, version,\n * compatibility requirements, and provided services.\n */\npublic final class ExtensionDescriptorDTO {\n  private final String id;\n  private final String version;\n  private final String name;\n  private final String description;\n  private final Path jarPath;\n  private final String btraceApiVersion;\n  private final String javaVersion;\n  private final List<String> services;\n  private final List<String> requiredExtensions;\n  private final ExtensionRepository repository;\n  private final PermissionSet requiredPermissions;\n\n  private volatile boolean loaded = false;\n  private volatile ClassLoader classLoader = null;\n\n  ExtensionDescriptorDTO(\n      String id,\n      String version,\n      String name,\n      String description,\n      Path jarPath,\n      String btraceApiVersion,\n      String javaVersion,\n      List<String> services,\n      List<String> requiredExtensions,\n      ExtensionRepository repository,\n      PermissionSet requiredPermissions) {\n    this.id = Objects.requireNonNull(id, \"Extension id cannot be null\");\n    this.version = Objects.requireNonNull(version, \"Extension version cannot be null\");\n    this.name = name != null ? name : id;\n    this.description = description != null ? description : \"\";\n    this.jarPath = Objects.requireNonNull(jarPath, \"Extension jar path cannot be null\");\n    this.btraceApiVersion = btraceApiVersion != null ? btraceApiVersion : \"2.0+\";\n    this.javaVersion = javaVersion != null ? javaVersion : \"8+\";\n    this.services = services != null ? Collections.unmodifiableList(services) : Collections.emptyList();\n    this.requiredExtensions = requiredExtensions != null ? Collections.unmodifiableList(requiredExtensions) : Collections.emptyList();\n    this.repository = repository;\n    this.requiredPermissions = requiredPermissions != null ? requiredPermissions : PermissionSet.empty();\n  }\n\n  public String getId() {\n    return id;\n  }\n\n  public String getVersion() {\n    return version;\n  }\n\n  public String getName() {\n    return name;\n  }\n\n  public String getDescription() {\n    return description;\n  }\n\n  public Path getJarPath() {\n    return jarPath;\n  }\n\n  public String getBtraceApiVersion() {\n    return btraceApiVersion;\n  }\n\n  public String getJavaVersion() {\n    return javaVersion;\n  }\n\n  public List<String> getServices() {\n    return services;\n  }\n\n  public List<String> getRequiredExtensions() {\n    return requiredExtensions;\n  }\n\n  public ExtensionRepository getRepository() {\n    return repository;\n  }\n\n  /**\n   * Returns permissions required by this extension (from manifest or properties),\n   * or an empty set if none were declared.\n   */\n  public PermissionSet getRequiredPermissions() {\n    return requiredPermissions;\n  }\n\n  public boolean isLoaded() {\n    return loaded;\n  }\n\n  public ClassLoader getClassLoader() {\n    return classLoader;\n  }\n\n  public void setClassLoader(ClassLoader classLoader) {\n    this.classLoader = classLoader;\n    this.loaded = true;\n  }\n\n  /**\n   * Check if this extension provides the given service class.\n   *\n   * @param serviceClassName fully qualified service class name\n   * @return true if this extension provides the service\n   */\n  public boolean providesService(String serviceClassName) {\n    return services.contains(serviceClassName);\n  }\n\n  @Override\n  public boolean equals(Object o) {\n    if (this == o) return true;\n    if (o == null || getClass() != o.getClass()) return false;\n    ExtensionDescriptorDTO that = (ExtensionDescriptorDTO) o;\n    return id.equals(that.id) && version.equals(that.version);\n  }\n\n  @Override\n  public int hashCode() {\n    return Objects.hash(id, version);\n  }\n\n  @Override\n  public String toString() {\n    return \"ExtensionDescriptor{\"\n        + \"id='\"\n        + id\n        + '\\''\n        + \", version='\"\n        + version\n        + '\\''\n        + \", name='\"\n        + name\n        + '\\''\n        + \", jarPath=\"\n        + jarPath\n        + \", loaded=\"\n        + loaded\n        + '}';\n  }\n\n  /** Builder for creating ExtensionDescriptor instances. */\n  public static final class Builder {\n    private String id;\n    private String version;\n    private String name;\n    private String description;\n    private Path jarPath;\n    private String btraceApiVersion;\n    private String javaVersion;\n    private List<String> services;\n    private List<String> requiredExtensions;\n    private ExtensionRepository repository;\n    private PermissionSet requiredPermissions;\n\n    public Builder id(String id) {\n      this.id = id;\n      return this;\n    }\n\n    public Builder version(String version) {\n      this.version = version;\n      return this;\n    }\n\n    public Builder name(String name) {\n      this.name = name;\n      return this;\n    }\n\n    public Builder description(String description) {\n      this.description = description;\n      return this;\n    }\n\n    public Builder jarPath(Path jarPath) {\n      this.jarPath = jarPath;\n      return this;\n    }\n\n    public Builder btraceApiVersion(String btraceApiVersion) {\n      this.btraceApiVersion = btraceApiVersion;\n      return this;\n    }\n\n    public Builder javaVersion(String javaVersion) {\n      this.javaVersion = javaVersion;\n      return this;\n    }\n\n    public Builder services(List<String> services) {\n      this.services = services;\n      return this;\n    }\n\n    public Builder requiredExtensions(List<String> requiredExtensions) {\n      this.requiredExtensions = requiredExtensions;\n      return this;\n    }\n\n    public Builder repository(ExtensionRepository repository) {\n      this.repository = repository;\n      return this;\n    }\n\n    public Builder requiredPermissions(PermissionSet permissions) {\n      this.requiredPermissions = permissions;\n      return this;\n    }\n\n    public ExtensionDescriptorDTO build() {\n      return new ExtensionDescriptorDTO(\n          id,\n          version,\n          name,\n          description,\n          jarPath,\n          btraceApiVersion,\n          javaVersion,\n          services,\n          requiredExtensions,\n          repository,\n          requiredPermissions);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/ExtensionLoader.java",
    "content": "package org.openjdk.btrace.extension;\n\nimport org.openjdk.btrace.extension.impl.ExtensionConfig;\nimport org.openjdk.btrace.extension.impl.ExtensionLoaderImpl;\nimport org.openjdk.btrace.extension.impl.FileSystemExtensionRepository;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.lang.instrument.Instrumentation;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\npublic abstract class ExtensionLoader {\n    private static Logger log = LoggerFactory.getLogger(ExtensionLoader.class);\n\n    private static final AtomicReference<ExtensionLoaderImpl> implRef = new AtomicReference<>(null);\n\n    public static ExtensionLoader instance() {\n        return implRef.get();\n    }\n\n    public static ExtensionLoader initialize(String btraceHome, ClassLoader parentClassLoader, Instrumentation instrumentation) {\n        // Create extension repositories in priority order\n        List<ExtensionRepository> repositories = new ArrayList<>();\n\n        // 1. Built-in extensions (lowest priority)\n        Path builtinExtPath = new File(btraceHome, \"extensions\").toPath();\n        repositories.add(\n                new FileSystemExtensionRepository(builtinExtPath, ExtensionRepository.Priority.BUILTIN));\n\n        // 2. User extensions (~/.btrace/extensions/)\n        String userHome = System.getProperty(\"user.home\");\n        if (userHome != null) {\n            Path userExtPath = new File(userHome, \".btrace/extensions\").toPath();\n            repositories.add(\n                    new FileSystemExtensionRepository(userExtPath, ExtensionRepository.Priority.USER));\n        }\n\n        // 3. Environment variable BTRACE_EXT_PATH\n        String extPath = System.getenv(\"BTRACE_EXT_PATH\");\n        if (extPath != null && !extPath.isEmpty()) {\n            String[] paths = extPath.split(File.pathSeparator);\n            for (String path : paths) {\n                repositories.add(\n                        new FileSystemExtensionRepository(\n                                new File(path).toPath(), ExtensionRepository.Priority.ENVIRONMENT));\n            }\n        }\n\n        // Load extension configuration\n        if (log.isDebugEnabled()) {\n            log.debug(\"Loading extension config from: {}\", btraceHome);\n        }\n        ExtensionConfig config = ExtensionConfig.load(btraceHome);\n\n        ExtensionLoader instance =  new ExtensionLoaderImpl(repositories, parentClassLoader, config, instrumentation);\n        // Register service declaration resolver for bytecode-level validation.\n        // Bytecode verifier (instr) uses this to check @Injected fields without loading classes.\n        // Runtime reflection in Client#validateDeclaredServices complements this by checking\n        // actual loadability and module/classloader access in the target JVM.\n        ServiceDeclarationRegistry.setResolver(\n                fqcn -> instance.findExtensionForService(fqcn) != null);\n\n        // Discover all available extensions\n        if (log.isDebugEnabled()) {\n            log.debug(\"Discovering extensions...\");\n        }\n        instance.discoverExtensions();\n\n        if (log.isDebugEnabled()) {\n            log.debug(\"Extension system initialized with {} available extension(s)\",\n                    instance.getAvailableExtensions().size());\n        }\n        log.info(\"Extension system initialized with {} available extension(s)\",\n                instance.getAvailableExtensions().size());\n        return instance;\n    }\n\n    /**\n     * Find an extension that provides the given service class.\n     *\n     * @param serviceClassName fully qualified service class name\n     * @return extension descriptor, or null if not found\n     */\n    public abstract ExtensionDescriptorDTO findExtensionForService(String serviceClassName);\n\n    /**\n     * Discover all available extensions from configured repositories.\n     * This should be called once during agent startup.\n     *\n     * @return list of discovered extensions\n     */\n    public abstract List<ExtensionDescriptorDTO> discoverExtensions();\n\n    /**\n     * Get all available (discovered) extensions.\n     *\n     * @return collection of available extension descriptors\n     */\n    public abstract Collection<ExtensionDescriptorDTO> getAvailableExtensions();\n\n    /**\n     * Ensure the extension API JAR is appended to the bootstrap classpath without\n     * attempting to load the implementation JAR. This enables BTrace to generate\n     * shims against the API when implementation use is blocked (e.g., permissions).\n     *\n     * @param descriptor the extension descriptor\n     * @return true if the API JAR was found and appended; false otherwise\n     */\n    public abstract boolean ensureApiOnBootstrap(ExtensionDescriptorDTO descriptor);\n\n    /**\n     * Load an extension and make its classes available.\n     * This is idempotent - loading an already-loaded extension is a no-op.\n     *\n     * @param descriptor extension to load\n     * @return true if loaded successfully, false otherwise\n     */\n    public abstract boolean load(ExtensionDescriptorDTO descriptor);\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/ExtensionRegistry.java",
    "content": "package org.openjdk.btrace.extension;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Minimal failure registry for extensions discovered/loaded via manifest-based loader.\n *\n * <p>Manifest and extension properties are the single source of truth. Extension discovery,\n * permission checks, and instantiation are handled by the manifest-based bridge/loader. This class\n * only exposes a stable map of failure reasons for diagnostics and UI.\n */\npublic final class ExtensionRegistry {\n  private ExtensionRegistry() {}\n\n  private static final ConcurrentHashMap<String, String> failedExtensions = new ConcurrentHashMap<>();\n\n  public static Map<String, String> getFailedExtensions() {\n    return Collections.unmodifiableMap(failedExtensions);\n  }\n\n  public static void registerFailedExtension(String idOrName, String reason) {\n    failedExtensions.put(idOrName, reason);\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/ExtensionRepository.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extension;\n\nimport java.util.List;\n\n/**\n * Repository for discovering BTrace extensions.\n * Implementations scan specific locations (file system directories,\n * remote repositories, etc.) for extension JARs and parse their metadata.\n */\npublic interface ExtensionRepository {\n\n  /**\n   * Scan this repository for available extensions.\n   *\n   * @return list of discovered extension descriptors\n   */\n  List<ExtensionDescriptorDTO> scan();\n\n  /**\n   * Get the location identifier for this repository (e.g., directory path, URL).\n   *\n   * @return repository location\n   */\n  String getLocation();\n\n  /**\n   * Get the priority of this repository. Higher priority repositories\n   * override lower priority ones when resolving extension conflicts.\n   * Built-in repositories have lower priority than user repositories.\n   *\n   * @return repository priority (higher = more important)\n   */\n  int getPriority();\n\n  /** Priority constants for common repository types. */\n  public static final class Priority {\n    /** Built-in extensions in BTRACE_HOME/libs/ext/ */\n    public static final int BUILTIN = 0;\n\n    /** System-wide extensions in /etc/btrace/ext/ or %PROGRAMDATA%\\btrace\\ext\\ */\n    public static final int SYSTEM = 100;\n\n    /** User extensions in ~/.btrace/ext/ */\n    public static final int USER = 200;\n\n    /** Environment variable BTRACE_EXT_PATH */\n    public static final int ENVIRONMENT = 300;\n\n    /** Command-line --ext-path argument */\n    public static final int COMMAND_LINE = 400;\n\n    /** Script-local ./.btrace/ext/ */\n    public static final int SCRIPT_LOCAL = 500;\n\n    private Priority() {}\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/PermissionPolicy.java",
    "content": "package org.openjdk.btrace.extension;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.InputStream;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Minimal process-wide policy: per-extension allow/deny plus a global allowPrivileged flag.\n *\n * <p>Used to decide whether an extension implementation may be linked. API classes remain\n * available for SHIMs when implementation is blocked.</p>\n */\npublic final class PermissionPolicy {\n  private static final Logger log = LoggerFactory.getLogger(PermissionPolicy.class);\n  private static final PermissionPolicy INSTANCE = new PermissionPolicy();\n\n  public static PermissionPolicy get() {\n    return INSTANCE;\n  }\n\n  // allow/deny lists (extension IDs) - use thread-safe sets\n  private final Set<String> allowExtIds = ConcurrentHashMap.newKeySet();\n  private final Set<String> denyExtIds = ConcurrentHashMap.newKeySet();\n\n  // global switch to allow all privileged extensions\n  private volatile boolean allowPrivileged = false;\n\n  private PermissionPolicy() {}\n\n  public void setAllowExtensionsCsv(String csv) {\n    parseCsvInto(csv, allowExtIds);\n  }\n\n  public void setDenyExtensionsCsv(String csv) {\n    parseCsvInto(csv, denyExtIds);\n  }\n\n  public void setAllowPrivileged(boolean allow) {\n    this.allowPrivileged = allow;\n  }\n\n  private static void parseCsvInto(String csv, Set<String> target) {\n    if (csv == null || csv.trim().isEmpty()) return;\n    for (String s : csv.split(\",\")) {\n      String v = s.trim();\n      if (!v.isEmpty()) target.add(v);\n    }\n  }\n\n  public void loadFromDefaults() {\n    String source = null;\n    try {\n      Properties props = new Properties();\n\n      // 1) explicit system property path\n      String path = System.getProperty(\"btrace.permissions\");\n      if (path != null && !path.isEmpty()) {\n        File f = new File(path);\n        if (f.exists()) {\n          try (InputStream is = new FileInputStream(f)) {\n            props.load(is);\n            source = f.getAbsolutePath();\n          }\n        }\n      }\n\n      // 2) user home locations\n      if (source == null) {\n        String home = System.getProperty(\"user.home\");\n        if (home != null) {\n          File f1 = new File(home, \".btrace/permissions.properties\");\n          File f2 = new File(home, \".config/btrace/permissions.properties\");\n          File fx = f1.exists() ? f1 : (f2.exists() ? f2 : null);\n          if (fx != null) {\n            try (InputStream is = new FileInputStream(fx)) {\n              props.load(is);\n              source = fx.getAbsolutePath();\n            }\n          }\n        }\n      }\n\n      // 3) classpath resource\n      if (source == null) {\n        InputStream is = ClassLoader.getSystemResourceAsStream(\"META-INF/btrace/permissions.properties\");\n        if (is != null) {\n          try (InputStream ris = is) {\n            props.load(ris);\n            source = \"classpath:META-INF/btrace/permissions.properties\";\n          }\n        }\n      }\n\n      if (source != null) {\n        parseProperties(props);\n        if (log.isInfoEnabled()) {\n          log.info(\"Loaded BTrace permission policy from {}\", source);\n        }\n      } else {\n        if (log.isDebugEnabled()) {\n          log.debug(\"No BTrace permission policy found; using defaults\");\n        }\n      }\n    } catch (Exception e) {\n      log.warn(\"Failed to load BTrace permission policy: {}\", e.getMessage());\n    }\n  }\n\n  private void parseProperties(Properties props) {\n    setAllowExtensionsCsv(props.getProperty(\"allowExtensions\", \"\"));\n    setDenyExtensionsCsv(props.getProperty(\"denyExtensions\", \"\"));\n    String ap = props.getProperty(\"allowPrivileged\", \"false\");\n    setAllowPrivileged(Boolean.parseBoolean(ap));\n  }\n\n  public boolean isExplicitlyDenied(String extensionId) {\n    return extensionId != null && denyExtIds.contains(extensionId);\n  }\n\n  public boolean isExplicitlyAllowed(String extensionId) {\n    return extensionId != null && allowExtIds.contains(extensionId);\n  }\n\n  public boolean isAllowPrivileged() {\n    return allowPrivileged;\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/ServiceDeclarationRegistry.java",
    "content": "package org.openjdk.btrace.extension;\n\n/**\n * Pluggable registry to validate whether a given service type is declared\n * by any available BTrace extension.\n *\n * How it is used:\n * - The agent wires a resolver at startup based on its ExtensionLoader; see\n *   agent initialization. This lets bytecode-time validation (e.g., in\n *   BTraceProbeNode) query declared services without loading any user classes.\n * - This check is intentionally lightweight and name-based. It complements the\n *   runtime reflection validation in the agent (Client#validateDeclaredServices),\n *   which runs in the actual target JVM and covers classloader identity, JPMS\n *   access, and linkage/loadability.\n *\n * When unset, validation defaults to permissive to avoid blocking in environments\n * where the agent has not configured the resolver (e.g., tooling or tests that\n * do not initialize extensions).\n */\npublic final class ServiceDeclarationRegistry {\n  private ServiceDeclarationRegistry() {}\n\n  public interface Resolver {\n    boolean isDeclaredService(String fqcn);\n  }\n\n  private static volatile Resolver resolver;\n\n  public static void setResolver(Resolver r) {\n    resolver = r;\n  }\n\n  public static boolean isDeclaredService(String fqcn) {\n    Resolver r = resolver;\n    if (r == null) {\n      return true; // permissive by default if not configured\n    }\n    try {\n      return r.isDeclaredService(fqcn);\n    } catch (Throwable t) {\n      return true; // do not block if resolver fails\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/impl/ExtensionBridgeImpl.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extension.impl;\n\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.core.extensions.PermissionSet;\nimport org.openjdk.btrace.extension.ExtensionBridge;\nimport org.openjdk.btrace.extension.ExtensionDescriptorDTO;\nimport org.openjdk.btrace.extension.ExtensionLoader;\nimport org.openjdk.btrace.extension.PermissionPolicy;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Implementation of ExtensionBridge for agent-side extension access.\n * Provides class loading for extension services accessed via invokedynamic.\n */\npublic final class ExtensionBridgeImpl implements ExtensionBridge {\n  private static final Logger log = LoggerFactory.getLogger(ExtensionBridgeImpl.class);\n\n  private final ExtensionLoader loader;\n\n  public ExtensionBridgeImpl(ExtensionLoader loader) {\n    this.loader = loader;\n  }\n\n  /** Initialize the invokedynamic bridge with a live ExtensionLoader. */\n  public static void initialize(ExtensionLoader loader) {\n    try {\n      Class<?> indyClz = Class.forName(\"org.openjdk.btrace.runtime.ExtensionIndy\");\n      ExtensionBridge bridge = new ExtensionBridgeImpl(loader);\n      indyClz.getField(\"bridge\").set(null, bridge);\n      log.debug(\"ExtensionIndy.bridge initialized\");\n    } catch (ClassNotFoundException e) {\n      log.debug(\"ExtensionIndy not available (expected for older Java versions)\");\n    } catch (Throwable t) {\n      log.warn(\"Unable to initialize ExtensionIndy.bridge\", t);\n    }\n  }\n\n  @Override\n  public Class<?> getExtensionClass(String serviceClassName) throws Exception {\n    // 1) Locate the providing extension\n    ExtensionDescriptorDTO ext = loader.findExtensionForService(serviceClassName);\n    if (ext == null) {\n      log.error(\"No extension found providing service: {}\", serviceClassName);\n      org.openjdk.btrace.extension.ExtensionRegistry.registerFailedExtension(serviceClassName, \"No providing extension found\");\n      return null;\n    }\n    if (log.isDebugEnabled()) {\n      log.debug(\"ExtensionBridge: service {} provided by extension {} at {} (loaded={})\",\n          serviceClassName, ext.getId(), ext.getJarPath(), ext.isLoaded());\n    }\n\n    // 2) Enforce policy (deny list / privileged requirements)\n    PermissionPolicy policy = PermissionPolicy.get();\n    if (policy.isExplicitlyDenied(ext.getId())) {\n      return fallbackInterface(ext, serviceClassName, \"Blocked by policy (denyExtensions)\");\n    }\n    if (requiresPrivileged(ext) && !(policy.isAllowPrivileged() || policy.isExplicitlyAllowed(ext.getId()))) {\n      log.warn(\"Blocking privileged extension {}. Allow via allowExtensions or allowPrivileged.\", ext.getId());\n      return fallbackInterface(ext, serviceClassName, \"Blocked privileged extension. Required=\" + ext.getRequiredPermissions());\n    }\n\n    // 3) Load extension if needed\n    if (!ext.isLoaded()) {\n      if (!loader.load(ext)) {\n        log.error(\"Failed to load extension {} for service {}\", ext.getId(), serviceClassName);\n        org.openjdk.btrace.extension.ExtensionRegistry.registerFailedExtension(ext.getId(), \"Failed to load extension\");\n        return null;\n      }\n    }\n\n    // 4) Resolve implementation class from extension classloader\n    ClassLoader extCl = ext.getClassLoader();\n    if (extCl == null) {\n      log.error(\"Extension {} has no classloader\", ext.getId());\n      return null;\n    }\n    Class<?> serviceInterface = extCl.loadClass(serviceClassName);\n    Class<?> impl = findImplementationClass(serviceInterface, extCl);\n    if (impl != null) return impl;\n\n    // 5) Try context classloader as a relaxed fallback (useful in tests)\n    try {\n      ClassLoader tccl = Thread.currentThread().getContextClassLoader();\n      if (tccl != null && tccl != extCl) {\n        Class<?> altIface = tccl.loadClass(serviceInterface.getName());\n        Class<?> altImpl = findImplementationClass(altIface, tccl);\n        if (altImpl != null) return altImpl;\n      }\n    } catch (Throwable ignore) {\n      // ignore and fall back to interface\n    }\n\n    // 6) Fallback to service interface (runtime will shim as needed)\n    if (log.isDebugEnabled()) {\n      log.debug(\"ExtensionBridge: falling back to interface {} for service {}\", serviceInterface.getName(), serviceClassName);\n    }\n    return serviceInterface;\n  }\n\n  private boolean requiresPrivileged(ExtensionDescriptorDTO ext) {\n    PermissionSet required = ext.getRequiredPermissions();\n    if (required == null) return false;\n    for (Permission p : required) {\n      if (p.isPrivileged()) return true;\n    }\n    return false;\n  }\n\n  private Class<?> fallbackInterface(ExtensionDescriptorDTO ext, String serviceClassName, String reason) {\n    try {\n      loader.ensureApiOnBootstrap(ext);\n      Class<?> intf = Class.forName(serviceClassName, false, null);\n      org.openjdk.btrace.extension.ExtensionRegistry.registerFailedExtension(ext.getId(), reason);\n      return intf;\n    } catch (ClassNotFoundException cnfe) {\n      // Even if API interface is not on bootstrap in this environment, keep the original reason\n      // to accurately reflect why the implementation was not linked.\n      org.openjdk.btrace.extension.ExtensionRegistry.registerFailedExtension(ext.getId(), reason);\n      return null;\n    }\n  }\n\n  private Class<?> findImplementationClass(Class<?> serviceInterface, ClassLoader cl) {\n    String ifaceName = serviceInterface.getName();\n    // Prefer ServiceLoader to allow multiple providers and custom impl names\n    try {\n      java.util.ServiceLoader<?> sl = java.util.ServiceLoader.load(serviceInterface, cl);\n      for (Object prov : sl) {\n        Class<?> impl = prov.getClass();\n        if (serviceInterface.isAssignableFrom(impl)) {\n          if (log.isDebugEnabled()) {\n            log.debug(\"ExtensionBridge: using ServiceLoader provider {} for service {}\", impl.getName(), ifaceName);\n          }\n          return impl;\n        }\n      }\n    } catch (Throwable t) {\n      // ignore and continue\n    }\n\n    // Conventional Impl naming: FooService -> FooServiceImpl\n    String implCandidate = ifaceName + \"Impl\";\n    try {\n      Class<?> impl = cl.loadClass(implCandidate);\n      if (serviceInterface.isAssignableFrom(impl)) {\n        if (log.isDebugEnabled()) {\n          log.debug(\"ExtensionBridge: using Impl candidate {} for service {}\", implCandidate, ifaceName);\n        }\n        return impl;\n      }\n    } catch (ClassNotFoundException ignore) {\n      // no-op\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/impl/ExtensionClassLoader.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extension.impl;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\n\n/**\n * ClassLoader for BTrace extensions.\n * Each extension is loaded in its own classloader for isolation.\n * The parent classloader should be the BTrace boot classloader that\n * contains core BTrace API classes.\n *\n * <p>Delegation model:\n * <pre>\n * Bootstrap ClassLoader (JRE classes)\n *     ↓\n * BTrace Boot ClassLoader (btrace-boot.jar - core API)\n *     ↓\n * Extension ClassLoader (extension JAR - extension code + shaded deps)\n * </pre>\n *\n * <p>Extensions can see:\n * - JRE classes (bootstrap)\n * - BTrace core API classes (parent)\n * - Their own classes and shaded dependencies (this classloader)\n *\n * <p>Extensions cannot see:\n * - Other extension's classes\n * - Agent implementation classes\n */\npublic final class ExtensionClassLoader extends URLClassLoader {\n  private final String extensionId;\n  private final String extensionVersion;\n\n  /**\n   * Create an extension classloader.\n   *\n   * @param extensionId extension identifier\n   * @param extensionVersion extension version\n   * @param urls URLs to load extension classes from (typically single JAR)\n   * @param parent parent classloader (typically BTrace boot classloader)\n   */\n  public ExtensionClassLoader(\n      String extensionId, String extensionVersion, URL[] urls, ClassLoader parent) {\n    super(urls, parent);\n    this.extensionId = extensionId;\n    this.extensionVersion = extensionVersion;\n  }\n\n  /**\n   * Get the extension identifier.\n   *\n   * @return extension ID\n   */\n  public String getExtensionId() {\n    return extensionId;\n  }\n\n  /**\n   * Get the extension version.\n   *\n   * @return extension version\n   */\n  public String getExtensionVersion() {\n    return extensionVersion;\n  }\n\n  @Override\n  public String toString() {\n    return \"ExtensionClassLoader{\"\n        + \"extension='\"\n        + extensionId\n        + \"' version='\"\n        + extensionVersion\n        + \"'}\";\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/impl/ExtensionConfig.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extension.impl;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Properties;\nimport java.util.Set;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Configuration for BTrace extension loading and behavior.\n * Supports whitelisting, blacklisting, and extension-specific settings.\n */\npublic final class ExtensionConfig {\n  private static final Logger log = LoggerFactory.getLogger(ExtensionConfig.class);\n\n  private static final String PROP_ENABLED = \"extensions.enabled\";\n  private static final String PROP_DISABLED = \"extensions.disabled\";\n  private static final String PROP_AUTOLOAD = \"extensions.autoload\";\n\n  private final Set<String> enabledExtensions;\n  private final Set<String> disabledExtensions;\n  private final boolean autoload;\n  private final Properties allProperties;\n\n  private ExtensionConfig(\n      Set<String> enabledExtensions,\n      Set<String> disabledExtensions,\n      boolean autoload,\n      Properties allProperties) {\n    this.enabledExtensions = enabledExtensions;\n    this.disabledExtensions = disabledExtensions;\n    this.autoload = autoload;\n    this.allProperties = allProperties;\n  }\n\n  /**\n   * Load configuration from default locations.\n   * Priority: command-line {@literal >} user config {@literal >} system config {@literal >} defaults\n   *\n   * @param btraceHome BTRACE_HOME directory (for system config)\n   * @return loaded configuration\n   */\n  public static ExtensionConfig load(String btraceHome) {\n    // 1. Check command-line override\n    String configPath = System.getProperty(\"btrace.extensions.config\");\n    if (configPath != null) {\n      File configFile = new File(configPath);\n      if (configFile.exists()) {\n        log.info(\"Loading extension configuration from: {}\", configPath);\n        return loadFrom(configFile.toPath());\n      } else {\n        log.warn(\"Extension configuration file not found: {}\", configPath);\n      }\n    }\n\n    // 2. Check user config\n    String userHome = System.getProperty(\"user.home\");\n    if (userHome != null) {\n      Path userConfig = Paths.get(userHome, \".btrace\", \"extensions.conf\");\n      if (Files.exists(userConfig)) {\n        log.info(\"Loading extension configuration from: {}\", userConfig);\n        return loadFrom(userConfig);\n      }\n    }\n\n    // 3. Check system config\n    if (btraceHome != null) {\n      Path systemConfig = Paths.get(btraceHome, \"conf\", \"extensions.conf\");\n      if (Files.exists(systemConfig)) {\n        log.info(\"Loading extension configuration from: {}\", systemConfig);\n        return loadFrom(systemConfig);\n      }\n    }\n\n    // 4. Use defaults\n    log.debug(\"No extension configuration found, using defaults\");\n    return createDefault();\n  }\n\n  /**\n   * Load configuration from a specific file.\n   *\n   * @param configPath path to configuration file\n   * @return loaded configuration\n   */\n  public static ExtensionConfig loadFrom(Path configPath) {\n    Properties props = new Properties();\n    try (InputStream in = new FileInputStream(configPath.toFile())) {\n      props.load(in);\n    } catch (IOException e) {\n      log.error(\"Failed to load extension configuration from {}: {}\", configPath, e.getMessage());\n      return createDefault();\n    }\n\n    return parse(props);\n  }\n\n  /**\n   * Create default configuration (all enabled, autoload).\n   */\n  public static ExtensionConfig createDefault() {\n    return new ExtensionConfig(\n        Collections.emptySet(),\n        Collections.emptySet(),\n        true,\n        new Properties());\n  }\n\n  /**\n   * Parse configuration from properties.\n   */\n  private static ExtensionConfig parse(Properties props) {\n    // Parse enabled list\n    Set<String> enabled = parseExtensionList(props.getProperty(PROP_ENABLED, \"\"));\n\n    // Parse disabled list\n    Set<String> disabled = parseExtensionList(props.getProperty(PROP_DISABLED, \"\"));\n\n    // Parse autoload\n    boolean autoload = Boolean.parseBoolean(props.getProperty(PROP_AUTOLOAD, \"true\"));\n\n    return new ExtensionConfig(enabled, disabled, autoload, props);\n  }\n\n  private static Set<String> parseExtensionList(String value) {\n    if (value == null || value.trim().isEmpty()) {\n      return Collections.emptySet();\n    }\n    Set<String> extensions = new HashSet<>();\n    for (String ext : value.split(\"[,\\\\s]+\")) {\n      String trimmed = ext.trim();\n      if (!trimmed.isEmpty()) {\n        extensions.add(trimmed);\n      }\n    }\n    return extensions;\n  }\n\n  /**\n   * Check if an extension is enabled by configuration.\n   *\n   * @param extensionId extension identifier\n   * @return true if extension should be loaded\n   */\n  public boolean isEnabled(String extensionId) {\n    // Disabled list takes precedence\n    if (disabledExtensions.contains(extensionId)) {\n      return false;\n    }\n\n    // If enabled list is empty, all extensions are enabled\n    // If enabled list is not empty, only listed extensions are enabled\n    return enabledExtensions.isEmpty() || enabledExtensions.contains(extensionId);\n  }\n\n  /**\n   * Get autoload setting.\n   *\n   * @return true if extensions should be loaded on demand, false to load all at startup\n   */\n  public boolean isAutoLoad() {\n    return autoload;\n  }\n\n  /**\n   * Get extension-specific properties.\n   * Returns properties with keys prefixed by {@literal <extension-id>}. \n   *\n   * @param extensionId extension identifier\n   * @return properties for this extension (without prefix)\n   */\n  public Properties getExtensionProperties(String extensionId) {\n    Properties result = new Properties();\n    String prefix = extensionId + \".\";\n\n    for (String key : allProperties.stringPropertyNames()) {\n      if (key.startsWith(prefix)) {\n        String unprefixedKey = key.substring(prefix.length());\n        result.setProperty(unprefixedKey, allProperties.getProperty(key));\n      }\n    }\n\n    return result;\n  }\n\n  @Override\n  public String toString() {\n    StringBuilder sb = new StringBuilder(\"ExtensionConfig{\");\n    sb.append(\"autoload=\").append(autoload);\n    if (!enabledExtensions.isEmpty()) {\n      sb.append(\", enabled=\").append(enabledExtensions);\n    }\n    if (!disabledExtensions.isEmpty()) {\n      sb.append(\", disabled=\").append(disabledExtensions);\n    }\n    sb.append(\"}\");\n    return sb.toString();\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/impl/ExtensionLoaderImpl.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extension.impl;\n\nimport org.openjdk.btrace.extension.ExtensionDescriptorDTO;\nimport org.openjdk.btrace.extension.ExtensionLoader;\nimport org.openjdk.btrace.extension.ExtensionRepository;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.instrument.Instrumentation;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.jar.JarFile;\nimport java.util.stream.Collectors;\n\n/**\n * Manages discovery, loading, and lifecycle of BTrace extensions.\n */\npublic final class ExtensionLoaderImpl extends ExtensionLoader {\n  private static final Logger log = LoggerFactory.getLogger(ExtensionLoaderImpl.class);\n\n  private final List<ExtensionRepository> repositories;\n  private final ClassLoader parentClassLoader;\n  private final ExtensionConfig config;\n  private final Instrumentation instrumentation;\n  private final Map<String, ExtensionDescriptorDTO> loadedExtensions;\n  private final Map<String, ExtensionDescriptorDTO> availableExtensions;\n\n  /**\n   * Create an extension loader.\n   *\n   * @param repositories extension repositories to scan\n   * @param parentClassLoader parent classloader for extensions (typically BTrace boot classloader)\n   * @param config extension configuration\n   * @param instrumentation instrumentation instance for adding to boot classpath\n   */\n  public ExtensionLoaderImpl(\n      List<ExtensionRepository> repositories,\n      ClassLoader parentClassLoader,\n      ExtensionConfig config,\n      Instrumentation instrumentation) {\n    this.repositories = new ArrayList<>(repositories);\n    this.parentClassLoader = parentClassLoader;\n    this.config = config != null ? config : ExtensionConfig.createDefault();\n    this.instrumentation = instrumentation;\n    this.loadedExtensions = new HashMap<>();\n    this.availableExtensions = new HashMap<>();\n  }\n\n  /**\n   * Discover all available extensions from configured repositories.\n   * This should be called once during agent startup.\n   *\n   * @return list of discovered extensions\n   */\n  @Override\n  public List<ExtensionDescriptorDTO> discoverExtensions() {\n    log.info(\"Discovering extensions from {} repositories (config: {})\",\n        repositories.size(), config);\n\n    List<ExtensionDescriptorDTO> discovered = new ArrayList<>();\n\n    for (ExtensionRepository repository : repositories) {\n      log.debug(\"Scanning repository: {}\", repository.getLocation());\n      try {\n        List<ExtensionDescriptorDTO> extensions = repository.scan();\n        discovered.addAll(extensions);\n      } catch (Exception e) {\n        log.error(\"Failed to scan repository {}: {}\", repository.getLocation(), e.getMessage(), e);\n      }\n    }\n\n    // Resolve conflicts (higher priority repository wins, or latest version within same priority)\n    List<ExtensionDescriptorDTO> resolved = resolveConflicts(discovered);\n\n    // Filter based on configuration (enabled/disabled lists)\n    List<ExtensionDescriptorDTO> filtered = new ArrayList<>();\n    for (ExtensionDescriptorDTO ext : resolved) {\n      if (config.isEnabled(ext.getId())) {\n        filtered.add(ext);\n      } else {\n        log.info(\"Extension {} disabled by configuration\", ext.getId());\n      }\n    }\n\n    // Store in available extensions map\n    availableExtensions.clear();\n    for (ExtensionDescriptorDTO ext : filtered) {\n      availableExtensions.put(ext.getId(), ext);\n    }\n\n    log.info(\"Discovered {} extension(s): {}\", filtered.size(),\n        filtered.stream().map(e -> e.getId() + \":\" + e.getVersion()).collect(Collectors.joining(\", \")));\n\n    // Load all extensions immediately to add them to bootstrap classpath\n    // This is required so BTrace scripts can reference extension classes\n    log.info(\"Loading discovered extensions to bootstrap classpath\");\n    for (ExtensionDescriptorDTO ext : filtered) {\n      if (!load(ext)) {\n        log.warn(\"Failed to load extension {}, scripts may not be able to use it\", ext.getId());\n      }\n    }\n\n    return filtered;\n  }\n\n  @Override\n  public ExtensionDescriptorDTO findExtensionForService(String serviceClassName) {\n    for (ExtensionDescriptorDTO ext : availableExtensions.values()) {\n      if (ext.providesService(serviceClassName)) {\n        return ext;\n      }\n    }\n    return null;\n  }\n\n  /**\n   * Load an extension and make its classes available.\n   * This is idempotent - loading an already-loaded extension is a no-op.\n   *\n   * @param descriptor extension to load\n   * @return true if loaded successfully, false otherwise\n   */\n  @Override\n  public boolean load(ExtensionDescriptorDTO descriptor) {\n    // Synchronize on descriptor to prevent concurrent loading of the same extension\n    synchronized (descriptor) {\n      if (descriptor.isLoaded()) {\n        log.debug(\"Extension {} is already loaded\", descriptor.getId());\n        return true;\n      }\n      return doLoad(descriptor);\n    }\n  }\n\n  private boolean doLoad(ExtensionDescriptorDTO descriptor) {\n    log.info(\"Loading extension: {} version {} from {}\",\n        descriptor.getId(), descriptor.getVersion(), descriptor.getJarPath());\n\n    try {\n      // Load any required extensions first\n      for (String requiredId : descriptor.getRequiredExtensions()) {\n        ExtensionDescriptorDTO required = availableExtensions.get(requiredId);\n        if (required == null) {\n          log.error(\"Required extension {} not found for {}\",\n              requiredId, descriptor.getId());\n          return false;\n        }\n        if (!load(required)) {\n          log.error(\"Failed to load required extension {} for {}\",\n              requiredId, descriptor.getId());\n          return false;\n        }\n      }\n\n      // Load extension from directory structure:\n      // extensions/extension-name/\n      //   extension-name-api.jar  (added to bootstrap classpath)\n      //   extension-name-impl.jar (loaded via extension classloader)\n\n      Path extensionDir = descriptor.getJarPath();\n      Path apiJar = findApiJar(extensionDir);\n      Path implJar = findImplJar(extensionDir, apiJar);\n\n      if (apiJar == null) {\n        throw new IllegalStateException(\"No API JAR found in \" + extensionDir);\n      }\n      if (implJar == null) {\n        throw new IllegalStateException(\"No implementation JAR found in \" + extensionDir);\n      }\n\n      // Add API JAR to bootstrap classpath\n      // Note: JarFile must be closed after appendToBootstrapClassLoaderSearch as the\n      // instrumentation API does not take ownership of the file handle\n      try (JarFile apiJarFile = new JarFile(apiJar.toFile())) {\n        instrumentation.appendToBootstrapClassLoaderSearch(apiJarFile);\n        log.debug(\"Added {} to bootstrap classpath\", apiJar.getFileName());\n      }\n\n      // Create classloader for implementation JAR\n      URL implUrl = implJar.toUri().toURL();\n      URLClassLoader classLoader = new URLClassLoader(new URL[] {implUrl}, parentClassLoader);\n\n      descriptor.setClassLoader(classLoader);\n      loadedExtensions.put(descriptor.getId(), descriptor);\n\n      log.info(\"Successfully loaded extension: {} version {} (api: {}, impl: {})\",\n          descriptor.getId(), descriptor.getVersion(),\n          apiJar.getFileName(), implJar.getFileName());\n\n      return true;\n\n    } catch (Exception e) {\n      log.error(\n          \"Failed to load extension {}: {}\", descriptor.getId(), e.getMessage(), e);\n      return false;\n    }\n  }\n\n  /**\n   * Ensure the extension API JAR is appended to the bootstrap classpath without\n   * attempting to load the implementation JAR. This enables BTrace to generate\n   * shims against the API when implementation use is blocked (e.g., permissions).\n   *\n   * @param descriptor the extension descriptor\n   * @return true if the API JAR was found and appended; false otherwise\n   */\n  @Override\n  public boolean ensureApiOnBootstrap(ExtensionDescriptorDTO descriptor) {\n    try {\n      Path extensionDir = descriptor.getJarPath();\n      Path apiJar = findApiJar(extensionDir);\n      if (apiJar == null) {\n        log.warn(\"No API JAR found for extension {} in {}\", descriptor.getId(), extensionDir);\n        return false;\n      }\n      // Note: JarFile must be closed after appendToBootstrapClassLoaderSearch as the\n      // instrumentation API does not take ownership of the file handle\n      try (JarFile apiJarFile = new JarFile(apiJar.toFile())) {\n        instrumentation.appendToBootstrapClassLoaderSearch(apiJarFile);\n        log.debug(\"Ensured API on bootstrap for extension {} via {}\", descriptor.getId(), apiJar.getFileName());\n      }\n      return true;\n    } catch (Exception e) {\n      log.warn(\"Failed to ensure API on bootstrap for {}: {}\", descriptor.getId(), e.getMessage(), e);\n      return false;\n    }\n  }\n\n  /**\n   * Find the API JAR in the extension directory.\n   */\n  private java.nio.file.Path findApiJar(java.nio.file.Path extensionDir) throws java.io.IOException {\n    try (java.nio.file.DirectoryStream<java.nio.file.Path> stream =\n        java.nio.file.Files.newDirectoryStream(extensionDir, \"*-api.jar\")) {\n      for (java.nio.file.Path path : stream) {\n        return path;\n      }\n    }\n    return null;\n  }\n\n  /**\n   * Find the implementation JAR. First try reading from API JAR manifest,\n   * then fall back to scanning directory.\n   */\n  private java.nio.file.Path findImplJar(java.nio.file.Path extensionDir, java.nio.file.Path apiJar)\n      throws java.io.IOException {\n    if (apiJar != null) {\n      try (java.util.jar.JarFile jar = new java.util.jar.JarFile(apiJar.toFile())) {\n        java.util.jar.Manifest manifest = jar.getManifest();\n        if (manifest != null) {\n          String implJarName = manifest.getMainAttributes().getValue(\"BTrace-Extension-Impl\");\n          if (implJarName != null) {\n            java.nio.file.Path implPath = extensionDir.resolve(implJarName);\n            if (java.nio.file.Files.exists(implPath)) {\n              return implPath;\n            }\n          }\n        }\n      }\n    }\n\n    // Fallback: scan directory for *-impl.jar\n    try (java.nio.file.DirectoryStream<java.nio.file.Path> stream =\n        java.nio.file.Files.newDirectoryStream(extensionDir, \"*-impl.jar\")) {\n      for (java.nio.file.Path path : stream) {\n        return path;\n      }\n    }\n    return null;\n  }\n\n  /**\n   * Get all loaded extensions.\n   *\n   * @return collection of loaded extension descriptors\n   */\n  public Collection<ExtensionDescriptorDTO> getLoadedExtensions() {\n    return new ArrayList<>(loadedExtensions.values());\n  }\n\n  /**\n   * Get all available (discovered) extensions.\n   *\n   * @return collection of available extension descriptors\n   */\n  @Override\n  public Collection<ExtensionDescriptorDTO> getAvailableExtensions() {\n    return new ArrayList<>(availableExtensions.values());\n  }\n\n  /**\n   * Get a specific extension by ID.\n   *\n   * @param extensionId extension identifier\n   * @return extension descriptor, or null if not found\n   */\n  public ExtensionDescriptorDTO getExtension(String extensionId) {\n    return availableExtensions.get(extensionId);\n  }\n\n  /**\n   * Resolve conflicts when multiple versions of the same extension are discovered.\n   * Resolution strategy:\n   * 1. Higher priority repository wins\n   * 2. Within same priority, latest version wins\n   *\n   * @param discovered list of all discovered extensions\n   * @return list of extensions with conflicts resolved\n   */\n  private List<ExtensionDescriptorDTO> resolveConflicts(List<ExtensionDescriptorDTO> discovered) {\n    // Group by extension ID\n    Map<String, List<ExtensionDescriptorDTO>> byId = new HashMap<>();\n    for (ExtensionDescriptorDTO ext : discovered) {\n      byId.computeIfAbsent(ext.getId(), k -> new ArrayList<>()).add(ext);\n    }\n\n    List<ExtensionDescriptorDTO> resolved = new ArrayList<>();\n\n    for (Map.Entry<String, List<ExtensionDescriptorDTO>> entry : byId.entrySet()) {\n      List<ExtensionDescriptorDTO> candidates = entry.getValue();\n\n      if (candidates.size() == 1) {\n        resolved.add(candidates.get(0));\n        continue;\n      }\n\n      // Multiple versions - resolve conflict\n      log.debug(\"Resolving conflict for extension {}: {} candidates\",\n          entry.getKey(), candidates.size());\n\n      ExtensionDescriptorDTO winner =\n          candidates.stream()\n              .max(\n                  Comparator.comparingInt((ExtensionDescriptorDTO e) -> e.getRepository().getPriority())\n                      .thenComparing(ExtensionDescriptorDTO::getVersion))\n              .orElse(null);\n\n      if (winner != null) {\n        log.info(\"Selected extension {} version {} from {} (priority {})\",\n            winner.getId(),\n            winner.getVersion(),\n            winner.getRepository().getLocation(),\n            winner.getRepository().getPriority());\n\n        resolved.add(winner);\n      }\n    }\n\n    return resolved;\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/impl/ExtensionMetadata.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extension.impl;\n\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.core.extensions.PermissionSet;\nimport org.openjdk.btrace.extension.ExtensionDescriptorDTO;\nimport org.openjdk.btrace.extension.ExtensionRepository;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.EnumSet;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\n/**\n * Parser for extension metadata from MANIFEST.MF attributes,\n * btrace-extension.properties (legacy), and META-INF/services files.\n */\nfinal class ExtensionMetadata {\n  private static final String METADATA_FILE = \"META-INF/btrace-extension.properties\";\n  private static final String SERVICES_DIR = \"META-INF/services/\";\n\n  // MANIFEST.MF attribute names\n  private static final String ATTR_EXTENSION_ID = \"BTrace-Extension-Id\";\n  private static final String ATTR_EXTENSION_VERSION = \"BTrace-Extension-Version\";\n  private static final String ATTR_EXTENSION_NAME = \"BTrace-Extension-Name\";\n  private static final String ATTR_EXTENSION_DESC = \"BTrace-Extension-Description\";\n  private static final String ATTR_API_VERSION = \"BTrace-API-Version\";\n  private static final String ATTR_JAVA_VERSION = \"BTrace-Java-Version\";\n  private static final String ATTR_SERVICES = \"BTrace-Extension-Services\";\n  private static final String ATTR_REQUIRES = \"BTrace-Extension-Requires\";\n  private static final String ATTR_PERMISSIONS = \"BTrace-Extension-Permissions\";\n\n  private ExtensionMetadata() {}\n\n  /**\n   * Parse extension metadata from a JAR file.\n   * Priority: MANIFEST.MF attributes > btrace-extension.properties > inference\n   *\n   * @param jarPath path to extension JAR\n   * @param repository repository this extension was discovered in\n   * @return extension descriptor, or null if not a valid extension\n   */\n  static ExtensionDescriptorDTO parse(Path jarPath, ExtensionRepository repository) {\n    return parse(jarPath, jarPath, repository);\n  }\n\n  /**\n   * Parse extension metadata from an API JAR in an extension directory.\n   * Priority: MANIFEST.MF attributes > btrace-extension.properties > inference\n   *\n   * @param apiJarPath path to extension API JAR\n   * @param extensionDirPath path to extension directory (used as jarPath in descriptor)\n   * @param repository repository this extension was discovered in\n   * @return extension descriptor, or null if not a valid extension\n   */\n  static ExtensionDescriptorDTO parse(Path apiJarPath, Path extensionDirPath, ExtensionRepository repository) {\n    try (JarFile jar = new JarFile(apiJarPath.toFile())) {\n      // Try MANIFEST.MF first\n      ExtensionDescriptorDTO fromManifest = parseFromManifest(extensionDirPath, jar, repository);\n      if (fromManifest != null) {\n        return fromManifest;\n      }\n\n      // Fall back to btrace-extension.properties\n      ExtensionDescriptorDTO fromProperties = parseFromProperties(extensionDirPath, jar, repository);\n      if (fromProperties != null) {\n        return fromProperties;\n      }\n\n      // Last resort: infer from JAR name and services\n      return inferMetadata(extensionDirPath, jar, repository);\n\n    } catch (IOException e) {\n      return null;\n    }\n  }\n\n  /**\n   * Parse extension metadata from MANIFEST.MF attributes.\n   */\n  private static ExtensionDescriptorDTO parseFromManifest(\n      Path jarPath, JarFile jar, ExtensionRepository repository) throws IOException {\n    Manifest manifest = jar.getManifest();\n    if (manifest == null) {\n      return null;\n    }\n\n    Attributes attrs = manifest.getMainAttributes();\n    String id = attrs.getValue(ATTR_EXTENSION_ID);\n    String version = attrs.getValue(ATTR_EXTENSION_VERSION);\n\n    if (id == null || version == null) {\n      // Not a BTrace extension (missing required attributes)\n      return null;\n    }\n\n    // Parse services from both manifest attribute and META-INF/services\n    List<String> services = new ArrayList<>();\n    String servicesAttr = attrs.getValue(ATTR_SERVICES);\n    if (servicesAttr != null && !servicesAttr.trim().isEmpty()) {\n      services.addAll(parseList(servicesAttr));\n    }\n    // Also scan META-INF/services directory\n    services.addAll(scanServicesDirectory(jar));\n\n    return new ExtensionDescriptorDTO.Builder()\n        .id(id)\n        .version(version)\n        .name(attrs.getValue(ATTR_EXTENSION_NAME) != null ?\n              attrs.getValue(ATTR_EXTENSION_NAME) : id)\n        .description(attrs.getValue(ATTR_EXTENSION_DESC) != null ?\n                     attrs.getValue(ATTR_EXTENSION_DESC) : \"\")\n        .jarPath(jarPath)\n        .btraceApiVersion(attrs.getValue(ATTR_API_VERSION) != null ?\n                          attrs.getValue(ATTR_API_VERSION) : \"2.0+\")\n        .javaVersion(attrs.getValue(ATTR_JAVA_VERSION) != null ?\n                     attrs.getValue(ATTR_JAVA_VERSION) : \"8+\")\n        .services(services)\n        .requiredExtensions(parseList(attrs.getValue(ATTR_REQUIRES)))\n        .requiredPermissions(parsePermissions(attrs.getValue(ATTR_PERMISSIONS)))\n        .repository(repository)\n        .build();\n  }\n\n  /**\n   * Parse extension metadata from btrace-extension.properties file (legacy).\n   */\n  private static ExtensionDescriptorDTO parseFromProperties(\n      Path jarPath, JarFile jar, ExtensionRepository repository) throws IOException {\n    Properties props = loadMetadata(jar);\n    if (props == null) {\n      return null;\n    }\n\n    String id = props.getProperty(\"extension.id\");\n    String version = props.getProperty(\"extension.version\");\n\n    if (id == null || version == null) {\n      // Invalid metadata\n      return null;\n    }\n\n    List<String> services = parseServices(jar, props);\n\n    return new ExtensionDescriptorDTO.Builder()\n        .id(id)\n        .version(version)\n        .name(props.getProperty(\"extension.name\", id))\n        .description(props.getProperty(\"extension.description\", \"\"))\n        .jarPath(jarPath)\n        .btraceApiVersion(props.getProperty(\"btrace.api.version\", \"2.0+\"))\n        .javaVersion(props.getProperty(\"java.version\", \"8+\"))\n        .services(services)\n        .requiredExtensions(parseList(props.getProperty(\"requires.extensions\", \"\")))\n        .requiredPermissions(parsePermissions(props.getProperty(\"requires.permissions\", \"\")))\n        .repository(repository)\n        .build();\n  }\n\n  private static Properties loadMetadata(JarFile jar) throws IOException {\n    JarEntry entry = jar.getJarEntry(METADATA_FILE);\n    if (entry == null) {\n      return null;\n    }\n\n    Properties props = new Properties();\n    try (InputStream in = jar.getInputStream(entry)) {\n      props.load(in);\n    }\n    return props;\n  }\n\n  /**\n   * Scan META-INF/services directory for service implementations.\n   */\n  private static List<String> scanServicesDirectory(JarFile jar) throws IOException {\n    List<String> services = new ArrayList<>();\n    Enumeration<JarEntry> entries = jar.entries();\n    while (entries.hasMoreElements()) {\n      JarEntry entry = entries.nextElement();\n      if (entry.getName().startsWith(SERVICES_DIR) && !entry.isDirectory()) {\n        try (InputStream in = jar.getInputStream(entry);\n            BufferedReader reader =\n                new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {\n          String line;\n          while ((line = reader.readLine()) != null) {\n            line = line.trim();\n            // Skip comments and empty lines\n            if (!line.isEmpty() && !line.startsWith(\"#\")) {\n              // Add the implementation class\n              if (!services.contains(line)) {\n                services.add(line);\n              }\n            }\n          }\n        }\n      }\n    }\n    return services;\n  }\n\n  private static List<String> parseServices(JarFile jar, Properties props) throws IOException {\n    List<String> services = new ArrayList<>();\n\n    // First check if services are listed in metadata\n    String servicesProp = props.getProperty(\"services\");\n    if (servicesProp != null && !servicesProp.trim().isEmpty()) {\n      services.addAll(parseList(servicesProp));\n    }\n\n    // Also scan META-INF/services directory\n    services.addAll(scanServicesDirectory(jar));\n\n    return services;\n  }\n\n  private static ExtensionDescriptorDTO inferMetadata(\n      Path jarPath, JarFile jar, ExtensionRepository repository) {\n    // Try to infer metadata from JAR name\n    String fileName = jarPath.getFileName().toString();\n    if (!fileName.endsWith(\".jar\")) {\n      return null;\n    }\n\n    // Remove .jar extension\n    String baseName = fileName.substring(0, fileName.length() - 4);\n\n    // Try to parse name-version pattern\n    String id = baseName;\n    String version = \"unknown\";\n\n    int dashIndex = baseName.lastIndexOf('-');\n    if (dashIndex > 0 && dashIndex < baseName.length() - 1) {\n      String potentialVersion = baseName.substring(dashIndex + 1);\n      // Check if it looks like a version (starts with digit)\n      if (!potentialVersion.isEmpty() && Character.isDigit(potentialVersion.charAt(0))) {\n        id = baseName.substring(0, dashIndex);\n        version = potentialVersion;\n      }\n    }\n\n    try {\n      List<String> services = scanServicesDirectory(jar);\n      if (services.isEmpty()) {\n        // No services found, not a valid extension\n        return null;\n      }\n\n      return new ExtensionDescriptorDTO.Builder()\n          .id(id)\n          .version(version)\n          .name(id)\n          .description(\"\")\n          .jarPath(jarPath)\n          .services(services)\n          .repository(repository)\n          .build();\n    } catch (IOException e) {\n      return null;\n    }\n  }\n\n  private static List<String> parseList(String value) {\n    if (value == null || value.trim().isEmpty()) {\n      return new ArrayList<>();\n    }\n    return Arrays.asList(value.split(\"[,\\\\s]+\"));\n  }\n\n  private static PermissionSet parsePermissions(String value) {\n    if (value == null || value.trim().isEmpty()) {\n      return PermissionSet.empty();\n    }\n    String[] parts = value.split(\"[,\\\\s]+\");\n    EnumSet<Permission> set = EnumSet.noneOf(Permission.class);\n    for (String p : parts) {\n      try {\n        set.add(Permission.valueOf(p.trim()));\n      } catch (IllegalArgumentException iae) {\n        // ignore unknown permission names to be lenient\n      }\n    }\n    if (set.isEmpty()) {\n      return PermissionSet.empty();\n    }\n    return PermissionSet.of(set.toArray(new Permission[0]));\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/impl/FileSystemExtensionRepository.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extension.impl;\n\nimport org.openjdk.btrace.extension.ExtensionDescriptorDTO;\nimport org.openjdk.btrace.extension.ExtensionRepository;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.nio.file.DirectoryStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Extension repository that scans a local file system directory for extension JARs.\n */\npublic final class FileSystemExtensionRepository implements ExtensionRepository {\n  private static final Logger log = LoggerFactory.getLogger(FileSystemExtensionRepository.class);\n\n  private final Path directory;\n  private final int priority;\n\n  /**\n   * Create a file system extension repository.\n   *\n   * @param directory directory to scan for extension JARs\n   * @param priority repository priority\n   */\n  public FileSystemExtensionRepository(Path directory, int priority) {\n    this.directory = directory;\n    this.priority = priority;\n  }\n\n  @Override\n  public List<ExtensionDescriptorDTO> scan() {\n    List<ExtensionDescriptorDTO> extensions = new ArrayList<>();\n\n    if (!Files.exists(directory)) {\n      log.debug(\"Extension directory does not exist: {}\", directory);\n      return extensions;\n    }\n\n    if (!Files.isDirectory(directory)) {\n      log.warn(\"Extension path is not a directory: {}\", directory);\n      return extensions;\n    }\n\n    log.debug(\"Scanning extension directory: {}\", directory);\n\n    try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory, Files::isDirectory)) {\n      for (Path extDir : stream) {\n        try {\n          // Look for API JAR in the extension directory\n          Path apiJar = findApiJar(extDir);\n          if (apiJar != null) {\n            // Parse metadata from API JAR but use extension directory as the base path\n            ExtensionDescriptorDTO descriptor = ExtensionMetadata.parse(apiJar, extDir, this);\n            if (descriptor != null) {\n              extensions.add(descriptor);\n              log.debug(\"Discovered extension: {} version {} from {}\",\n                  descriptor.getId(), descriptor.getVersion(), extDir.getFileName());\n            }\n          } else {\n            log.debug(\"Skipping directory without API JAR: {}\", extDir);\n          }\n        } catch (Exception e) {\n          log.warn(\"Failed to parse extension from {}: {}\", extDir, e.getMessage());\n        }\n      }\n    } catch (IOException e) {\n      log.error(\"Failed to scan extension directory {}: {}\", directory, e.getMessage());\n    }\n\n    log.info(\"Discovered {} extension(s) in {}\", extensions.size(), directory);\n    return extensions;\n  }\n\n  /**\n   * Find the API JAR in an extension directory.\n   */\n  private Path findApiJar(Path extensionDir) throws IOException {\n    try (DirectoryStream<Path> stream = Files.newDirectoryStream(extensionDir, \"*-api.jar\")) {\n      for (Path apiJar : stream) {\n        return apiJar;\n      }\n    }\n    return null;\n  }\n\n  @Override\n  public String getLocation() {\n    return directory.toString();\n  }\n\n  @Override\n  public int getPriority() {\n    return priority;\n  }\n\n  @Override\n  public String toString() {\n    return \"FileSystemExtensionRepository{\" + \"directory=\" + directory + \", priority=\" + priority + '}';\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/main/java/org/openjdk/btrace/extension/impl/NestedJarExtensionClassLoader.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.extension.impl;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.instrument.Instrumentation;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Extension classloader that loads from nested JAR structure.\n *\n * <p>Extension JARs contain two nested JARs:\n * <ul>\n *   <li>api.jar - API classes added to bootstrap classpath\n *   <li>impl.jar - Implementation classes loaded in this classloader\n * </ul>\n *\n * <p>This classloader extracts both nested JARs to a temp directory, adds the API JAR to\n * bootstrap classpath via Instrumentation, and loads implementation classes from impl.jar.\n */\npublic final class NestedJarExtensionClassLoader extends URLClassLoader {\n  private static final Logger log = LoggerFactory.getLogger(NestedJarExtensionClassLoader.class);\n\n  private final String extensionId;\n  private final String version;\n  private final Path apiJarPath;\n  private final Path implJarPath;\n  private final Path tempDir;\n\n  /**\n   * Create a nested JAR extension classloader.\n   *\n   * @param extensionId extension identifier\n   * @param version extension version\n   * @param extensionJar path to extension JAR containing api.jar and impl.jar\n   * @param parent parent classloader (typically BTrace boot classloader)\n   * @param instrumentation instrumentation instance for adding API to bootstrap classpath\n   * @throws IOException if nested JARs cannot be extracted\n   */\n  public NestedJarExtensionClassLoader(\n      String extensionId,\n      String version,\n      Path extensionJar,\n      ClassLoader parent,\n      Instrumentation instrumentation)\n      throws IOException {\n    super(new URL[0], parent);\n\n    this.extensionId = extensionId;\n    this.version = version;\n\n    // Create temp directory for this extension\n    this.tempDir = Files.createTempDirectory(\"btrace-ext-\" + extensionId + \"-\");\n    this.tempDir.toFile().deleteOnExit();\n\n    log.debug(\"Extracting nested JARs from {} to {}\", extensionJar, tempDir);\n\n    // Extract nested JARs\n    try (JarFile jar = new JarFile(extensionJar.toFile())) {\n      apiJarPath = extractNestedJar(jar, \"api.jar\", tempDir);\n      implJarPath = extractNestedJar(jar, \"impl.jar\", tempDir);\n    }\n\n    log.debug(\"Extracted api.jar to {} and impl.jar to {}\", apiJarPath, implJarPath);\n\n    // Add API JAR to bootstrap classpath\n    if (instrumentation != null) {\n      JarFile apiJar = new JarFile(apiJarPath.toFile());\n      instrumentation.appendToBootstrapClassLoaderSearch(apiJar);\n      log.info(\"Added extension API to bootstrap classpath: {} ({})\", extensionId, apiJarPath.getFileName());\n    } else {\n      log.warn(\"Instrumentation not available, cannot add API JAR to bootstrap: {}\", extensionId);\n    }\n\n    // Add impl JAR to this classloader's URLs\n    addURL(implJarPath.toUri().toURL());\n    log.debug(\"Added impl JAR to extension classloader: {}\", implJarPath);\n  }\n\n  /**\n   * Extract a nested JAR from the extension JAR.\n   *\n   * @param extensionJar the extension JAR file\n   * @param entryName name of nested JAR entry (e.g., \"api.jar\")\n   * @param targetDir directory to extract to\n   * @return path to extracted JAR file\n   * @throws IOException if extraction fails\n   */\n  private Path extractNestedJar(JarFile extensionJar, String entryName, Path targetDir)\n      throws IOException {\n    JarEntry entry = extensionJar.getJarEntry(entryName);\n    if (entry == null) {\n      throw new IOException(\n          String.format(\n              \"Nested JAR not found: %s in extension %s (%s)\",\n              entryName, extensionId, extensionJar.getName()));\n    }\n\n    Path targetFile = targetDir.resolve(entryName).normalize();\n    if (!targetFile.startsWith(targetDir)) {\n      throw new IOException(\"Zip Slip: entry would extract outside target dir: \" + entryName);\n    }\n    try (InputStream in = extensionJar.getInputStream(entry);\n        OutputStream out = Files.newOutputStream(targetFile)) {\n      byte[] buffer = new byte[8192];\n      int read;\n      while ((read = in.read(buffer)) != -1) {\n        out.write(buffer, 0, read);\n      }\n    }\n\n    targetFile.toFile().deleteOnExit();\n    log.debug(\"Extracted {} ({} bytes) to {}\", entryName, entry.getSize(), targetFile);\n\n    return targetFile;\n  }\n\n  public String getExtensionId() {\n    return extensionId;\n  }\n\n  public String getVersion() {\n    return version;\n  }\n\n  public Path getApiJarPath() {\n    return apiJarPath;\n  }\n\n  public Path getImplJarPath() {\n    return implJarPath;\n  }\n\n  @Override\n  public String toString() {\n    return String.format(\n        \"NestedJarExtensionClassLoader[%s:%s, api=%s, impl=%s]\",\n        extensionId, version, apiJarPath.getFileName(), implJarPath.getFileName());\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/test/java/org/openjdk/btrace/extension/ExtensionBridgeImplPolicyTest.java",
    "content": "package org.openjdk.btrace.extension;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.core.extensions.PermissionSet;\nimport org.openjdk.btrace.extension.impl.ExtensionBridgeImpl;\n\nimport java.nio.file.Paths;\nimport java.util.Collections;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass ExtensionBridgeImplPolicyTest {\n\n  private static final String EXT_ID_BASE = \"test-ext\";\n  private static final String SERVICE_IFACE = \"test.ext.Service\"; // with ServiceLoader provider\n  private static final String SERVICE_IFACE2 = \"test.ext2.Service2\"; // conventional Impl only\n\n  private static class DummyLoader extends ExtensionLoader {\n    final ExtensionDescriptorDTO desc;\n    boolean apiOnBoot;\n    boolean loaded;\n\n    DummyLoader(ExtensionDescriptorDTO desc) { this.desc = desc; }\n\n    @Override public ExtensionDescriptorDTO findExtensionForService(String serviceClassName) { return desc; }\n    @Override public java.util.List<ExtensionDescriptorDTO> discoverExtensions() { return Collections.singletonList(desc); }\n    @Override public java.util.Collection<ExtensionDescriptorDTO> getAvailableExtensions() { return Collections.singletonList(desc); }\n    @Override public boolean ensureApiOnBootstrap(ExtensionDescriptorDTO descriptor) { apiOnBoot = true; return true; }\n    @Override public boolean load(ExtensionDescriptorDTO descriptor) { loaded = true; return true; }\n  }\n\n  private ExtensionDescriptorDTO.Builder baseBuilder(String serviceFqcn, String extId) {\n    return new ExtensionDescriptorDTO.Builder()\n        .id(extId)\n        .version(\"1.0.0\")\n        .name(\"Test\")\n        .description(\"Test\")\n        .jarPath(Paths.get(\"/tmp/test.jar\"))\n        .services(Collections.singletonList(serviceFqcn))\n        .requiredExtensions(Collections.emptyList())\n        .repository(null)\n        .requiredPermissions(PermissionSet.empty());\n  }\n\n  @BeforeEach\n  void resetPolicy() {\n    PermissionPolicy p = PermissionPolicy.get();\n    p.setAllowExtensionsCsv(\"\");\n    p.setDenyExtensionsCsv(\"\");\n    p.setAllowPrivileged(false);\n  }\n\n  @Test\n  void denyListTriggersFallbackAndRegistersFailure() throws Exception {\n    String extId = EXT_ID_BASE + \"-deny\";\n    PermissionPolicy.get().setDenyExtensionsCsv(extId);\n    ExtensionDescriptorDTO dto = baseBuilder(SERVICE_IFACE, extId).build();\n    DummyLoader dl = new DummyLoader(dto);\n    ExtensionBridgeImpl bridge = new ExtensionBridgeImpl(dl);\n\n    Class<?> clz = bridge.getExtensionClass(SERVICE_IFACE);\n    assertNull(clz, \"Expected null when denied; serviceClass=\" + SERVICE_IFACE + \", extId=\" + extId);\n    assertTrue(dl.apiOnBoot, \"API should be ensured on bootstrap; extId=\" + extId);\n    assertFalse(dl.loaded, \"Implementation must not be loaded when denied; extId=\" + extId);\n    String reason = ExtensionRegistry.getFailedExtensions().get(extId);\n    assertEquals(\"Blocked by policy (denyExtensions)\", reason,\n        \"Unexpected failure reason for extId=\" + extId + \": \" + reason);\n  }\n\n  @Test\n  void privilegedWithoutAllowTriggersFallback() throws Exception {\n    String extId = EXT_ID_BASE + \"-priv\";\n    PermissionSet perms = PermissionSet.of(Permission.THREADS);\n    ExtensionDescriptorDTO dto = baseBuilder(SERVICE_IFACE, extId).requiredPermissions(perms).build();\n    DummyLoader dl = new DummyLoader(dto);\n    ExtensionBridgeImpl bridge = new ExtensionBridgeImpl(dl);\n\n    Class<?> clz = bridge.getExtensionClass(SERVICE_IFACE);\n    assertNull(clz, \"Expected null when privileged extension is not allowed; extId=\" + extId);\n    assertTrue(dl.apiOnBoot, \"API should be ensured on bootstrap for privileged fallback; extId=\" + extId);\n    assertFalse(dl.loaded, \"Privileged implementation should not be loaded when not allowed; extId=\" + extId);\n    String reason = ExtensionRegistry.getFailedExtensions().get(extId);\n    assertNotNull(reason, \"Expected a failure reason to be recorded; extId=\" + extId);\n    assertTrue(reason.startsWith(\"Blocked privileged extension.\"),\n        \"Unexpected failure reason for extId=\" + extId + \": \" + reason);\n  }\n\n  @Test\n  void allowedLoadsAndFindsConventionalImpl() throws Exception {\n    // Allow privileged to ensure no policy block\n    PermissionPolicy.get().setAllowPrivileged(true);\n    String extId = EXT_ID_BASE + \"-conv\";\n    ExtensionDescriptorDTO dto = baseBuilder(SERVICE_IFACE2, extId).build();\n    DummyLoader dl = new DummyLoader(dto);\n    // Use current classloader which has test classes\n    dto.setClassLoader(this.getClass().getClassLoader());\n    ExtensionBridgeImpl bridge = new ExtensionBridgeImpl(dl);\n\n    // Resolve conventional Impl for SERVICE_IFACE2\n    Class<?> impl2 = bridge.getExtensionClass(SERVICE_IFACE2);\n    assertNotNull(impl2, \"Expected conventional Impl to be resolved; service=\" + SERVICE_IFACE2 + \", extId=\" + extId + \", loaded=\" + dl.loaded);\n    assertEquals(\"test.ext2.Service2Impl\", impl2.getName(),\n        \"Resolved class name mismatch; got=\" + (impl2 != null ? impl2.getName() : \"null\"));\n  }\n\n  @Test\n  void allowedLoadsAndFindsServiceLoaderProvider() throws Exception {\n    PermissionPolicy.get().setAllowPrivileged(true);\n    String extId = EXT_ID_BASE + \"-spi\";\n    ExtensionDescriptorDTO dto = baseBuilder(SERVICE_IFACE, extId).build();\n    DummyLoader dl = new DummyLoader(dto);\n    dto.setClassLoader(this.getClass().getClassLoader());\n    ExtensionBridgeImpl bridge = new ExtensionBridgeImpl(dl);\n\n    Class<?> impl = bridge.getExtensionClass(SERVICE_IFACE);\n    assertNotNull(impl, \"Expected SPI provider to be resolved; service=\" + SERVICE_IFACE + \", extId=\" + extId + \", loaded=\" + dl.loaded);\n    assertEquals(\"test.ext.SpiImpl\", impl.getName(), \"SPI provider class name mismatch: \" + (impl != null ? impl.getName() : \"null\"));\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/test/java/org/openjdk/btrace/extension/ExtensionLoaderImplConcurrencyTest.java",
    "content": "package org.openjdk.btrace.extension;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.openjdk.btrace.core.extensions.PermissionSet;\nimport org.openjdk.btrace.extension.impl.ExtensionConfig;\nimport org.openjdk.btrace.extension.impl.ExtensionLoaderImpl;\n\nimport java.io.IOException;\nimport java.lang.instrument.ClassDefinition;\nimport java.lang.instrument.ClassFileTransformer;\nimport java.lang.instrument.Instrumentation;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ExtensionLoaderImplConcurrencyTest {\n  @TempDir\n  Path tempDir;\n\n  @Test\n  void loadIsIdempotentUnderConcurrency() throws Exception {\n    Path extDir = tempDir.resolve(\"test-ext\");\n    Files.createDirectories(extDir);\n\n    String implName = \"test-ext-impl.jar\";\n    Path apiJar = extDir.resolve(\"test-ext-api.jar\");\n    Path implJar = extDir.resolve(implName);\n    writeJar(apiJar, implName);\n    writeJar(implJar, null);\n\n    DummyInstrumentation instrumentation = new DummyInstrumentation();\n    ExtensionLoaderImpl loader =\n        new ExtensionLoaderImpl(\n            Collections.emptyList(),\n            getClass().getClassLoader(),\n            ExtensionConfig.createDefault(),\n            instrumentation);\n\n    ExtensionDescriptorDTO descriptor =\n        new ExtensionDescriptorDTO.Builder()\n            .id(\"test-ext\")\n            .version(\"1.0.0\")\n            .name(\"Test\")\n            .description(\"Test\")\n            .jarPath(extDir)\n            .services(List.of())\n            .requiredExtensions(List.of())\n            .repository(null)\n            .requiredPermissions(PermissionSet.empty())\n            .build();\n\n    int threads = 8;\n    CountDownLatch start = new CountDownLatch(1);\n    CountDownLatch done = new CountDownLatch(threads);\n    AtomicInteger success = new AtomicInteger();\n    ExecutorService executor = Executors.newFixedThreadPool(threads);\n    try {\n      for (int i = 0; i < threads; i++) {\n        executor.execute(\n            () -> {\n              try {\n                start.await();\n                if (loader.load(descriptor)) {\n                  success.incrementAndGet();\n                }\n              } catch (InterruptedException ignored) {\n                Thread.currentThread().interrupt();\n              } finally {\n                done.countDown();\n              }\n            });\n      }\n      start.countDown();\n      assertTrue(done.await(5, TimeUnit.SECONDS), \"Load operations did not finish in time\");\n    } finally {\n      executor.shutdownNow();\n    }\n\n    assertEquals(threads, success.get());\n    assertEquals(1, instrumentation.appendCount.get());\n    assertTrue(descriptor.isLoaded());\n    assertNotNull(descriptor.getClassLoader());\n    assertEquals(1, loader.getLoadedExtensions().size());\n  }\n\n  private static void writeJar(Path jarPath, String implJarName) throws IOException {\n    Manifest manifest = new Manifest();\n    Attributes attrs = manifest.getMainAttributes();\n    attrs.put(Attributes.Name.MANIFEST_VERSION, \"1.0\");\n    if (implJarName != null) {\n      attrs.putValue(\"BTrace-Extension-Impl\", implJarName);\n    }\n    try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(jarPath), manifest)) {\n      // empty jar is sufficient for loader tests\n    }\n  }\n\n  private static final class DummyInstrumentation implements Instrumentation {\n    private final AtomicInteger appendCount = new AtomicInteger();\n\n    @Override\n    public void addTransformer(ClassFileTransformer transformer, boolean canRetransform) {\n    }\n\n    @Override\n    public void addTransformer(ClassFileTransformer transformer) {\n    }\n\n    @Override\n    public boolean removeTransformer(ClassFileTransformer transformer) {\n      return false;\n    }\n\n    @Override\n    public boolean isRetransformClassesSupported() {\n      return false;\n    }\n\n    @Override\n    public void retransformClasses(Class<?>... classes) {\n    }\n\n    @Override\n    public boolean isRedefineClassesSupported() {\n      return false;\n    }\n\n    @Override\n    public void redefineClasses(ClassDefinition... definitions) {\n    }\n\n    @Override\n    public boolean isModifiableClass(Class<?> theClass) {\n      return false;\n    }\n\n    @Override\n    public Class<?>[] getAllLoadedClasses() {\n      return new Class<?>[0];\n    }\n\n    @Override\n    public Class<?>[] getInitiatedClasses(ClassLoader loader) {\n      return new Class<?>[0];\n    }\n\n    @Override\n    public long getObjectSize(Object objectToSize) {\n      return 0L;\n    }\n\n    @Override\n    public void appendToBootstrapClassLoaderSearch(JarFile jarfile) {\n      appendCount.incrementAndGet();\n    }\n\n    @Override\n    public void appendToSystemClassLoaderSearch(JarFile jarfile) {\n    }\n\n    @Override\n    public boolean isNativeMethodPrefixSupported() {\n      return false;\n    }\n\n    @Override\n    public void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {\n    }\n\n    @Override\n    public void redefineModule(\n        Module module,\n        Set<Module> extraReads,\n        Map<String, Set<Module>> extraExports,\n        Map<String, Set<Module>> extraOpens,\n        Set<Class<?>> extraUses,\n        Map<Class<?>, List<Class<?>>> extraProvides) {\n    }\n\n    @Override\n    public boolean isModifiableModule(Module module) {\n      return false;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-extension/src/test/java/test/ext/Service.java",
    "content": "package test.ext;\n\npublic interface Service {}\n\n"
  },
  {
    "path": "btrace-extension/src/test/java/test/ext/ServiceImpl.java",
    "content": "package test.ext;\n\npublic class ServiceImpl implements Service {}\n\n"
  },
  {
    "path": "btrace-extension/src/test/java/test/ext/SpiImpl.java",
    "content": "package test.ext;\n\npublic class SpiImpl implements Service {}\n\n"
  },
  {
    "path": "btrace-extension/src/test/java/test/ext2/Service2.java",
    "content": "package test.ext2;\n\npublic interface Service2 {}\n\n"
  },
  {
    "path": "btrace-extension/src/test/java/test/ext2/Service2Impl.java",
    "content": "package test.ext2;\n\npublic class Service2Impl implements Service2 {}\n\n"
  },
  {
    "path": "btrace-extension/src/test/resources/META-INF/services/test.ext.Service",
    "content": "test.ext.SpiImpl\n\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/build.gradle",
    "content": "plugins {\n    id 'org.openjdk.btrace.extension'\n    alias(libs.plugins.shadow)\n}\n\njava {\n    sourceCompatibility = 8\n    targetCompatibility = 8\n}\n\ncompileJava {\n    javaCompiler = javaToolchains.compilerFor {\n        languageVersion.set(JavaLanguageVersion.of(11))\n    }\n}\n\nbtraceExtension {\n    id = 'btrace-metrics'\n    name = 'BTrace HDR Histogram'\n    description = 'High-performance metrics using HdrHistogram for accurate percentile tracking'\n    services = ['org.openjdk.btrace.metrics.MetricsService']\n    shadedPackages = [\n        'org.HdrHistogram': 'org.openjdk.btrace.metrics.shaded.hdrhistogram',\n        'com.clearspring.analytics': 'org.openjdk.btrace.metrics.shaded.clearspring'\n    ]\n    // Strict lint is enabled by default; API exposes builders instead of public constructors\n}\n\ndependencies {\n    // API dependencies (no legacy services API)\n    apiCompileOnly 'org.jetbrains:annotations:26.1.0'\n    apiCompileOnly project(':btrace-core')\n    implCompileOnly 'org.jetbrains:annotations:26.1.0'\n\n    // Implementation dependencies (will be shaded)\n    implImplementation project(':btrace-core')\n    implImplementation libs.hdrhistogram\n    implImplementation libs.stream.lib\n\n    testImplementation libs.junit.jupiter\n    testImplementation libs.hdrhistogram\n}\n\ntest {\n    useJUnitPlatform()\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/api/java/org/openjdk/btrace/metrics/MetricsService.java",
    "content": "package org.openjdk.btrace.metrics;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.core.extensions.ServiceDescriptor;\nimport org.openjdk.btrace.metrics.histogram.HistogramConfig;\nimport org.openjdk.btrace.metrics.histogram.HistogramConfigBuilder;\nimport org.openjdk.btrace.metrics.histogram.HistogramMetric;\nimport org.openjdk.btrace.metrics.stats.StatsMetric;\n\n/**\n * High-performance metrics service API.\n */\n@ServiceDescriptor(permissions = { Permission.THREADS })\npublic interface MetricsService {\n  @Nullable HistogramConfigBuilder newHistogramConfig();\n  @Nullable HistogramMetric histogram(@NotNull String name);\n  @Nullable HistogramMetric histogram(@NotNull String name, @NotNull HistogramConfig config);\n  @Nullable HistogramMetric histogram(@NotNull String name, @NotNull String key);\n  @Nullable HistogramMetric histogram(@NotNull String name, @NotNull String key, @NotNull HistogramConfig config);\n  // Convenience creators for common units (matches prior constants):\n  @Nullable HistogramMetric histogramMicros(@NotNull String name);\n  @Nullable HistogramMetric histogramMicros(@NotNull String name, @NotNull String key);\n  @Nullable HistogramMetric histogramMillis(@NotNull String name);\n  @Nullable HistogramMetric histogramMillis(@NotNull String name, @NotNull String key);\n  @Nullable StatsMetric stats(@NotNull String name);\n  @Nullable StatsMetric stats(@NotNull String name, @NotNull String key);\n  void reset();\n  void clear();\n  int size();\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/api/java/org/openjdk/btrace/metrics/histogram/HistogramConfig.java",
    "content": "package org.openjdk.btrace.metrics.histogram;\n\n/**\n * Configuration for HdrHistogram.\n *\n * <p>Defines the range and precision of histogram measurements. Probes do not instantiate configs\n * directly; obtain a builder from the injected service and pass the built config handle back to the\n * service.\n */\npublic interface HistogramConfig {\n  long getLowestDiscernibleValue();\n  long getHighestTrackableValue();\n  int getNumberOfSignificantValueDigits();\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/api/java/org/openjdk/btrace/metrics/histogram/HistogramConfigBuilder.java",
    "content": "package org.openjdk.btrace.metrics.histogram;\n\n/** Builder for {@link HistogramConfig}. Obtain from the injected service. */\npublic interface HistogramConfigBuilder {\n  HistogramConfigBuilder lowestDiscernibleValue(long value);\n  HistogramConfigBuilder highestTrackableValue(long value);\n  HistogramConfigBuilder significantDigits(int digits);\n  HistogramConfig build();\n}\n\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/api/java/org/openjdk/btrace/metrics/histogram/HistogramMetric.java",
    "content": "package org.openjdk.btrace.metrics.histogram;\n\nimport org.jetbrains.annotations.Nullable;\n\npublic interface HistogramMetric {\n  void record(long value);\n  void recordValueWithCount(long value, long count);\n  @Nullable HistogramSnapshot snapshot();\n  void reset();\n  @Nullable String getName();\n}\n\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/api/java/org/openjdk/btrace/metrics/histogram/HistogramSnapshot.java",
    "content": "package org.openjdk.btrace.metrics.histogram;\n\nimport org.jetbrains.annotations.Nullable;\n\npublic interface HistogramSnapshot {\n  @Nullable String getName();\n  long p50();\n  long p75();\n  long p90();\n  long p95();\n  long p99();\n  long p999();\n  long p9999();\n  long percentile(double percentile);\n  long count();\n  long min();\n  long max();\n  double mean();\n  double stddev();\n}\n\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/api/java/org/openjdk/btrace/metrics/package-info.java",
    "content": "@ExtensionDescriptor(\n    name = \"btrace-metrics\",\n    version = \"1.0\",\n    description = \"High-performance metrics APIs\",\n    permissions = { Permission.THREADS }\n)\npackage org.openjdk.btrace.metrics;\n\nimport org.openjdk.btrace.core.extensions.ExtensionDescriptor;\nimport org.openjdk.btrace.core.extensions.Permission;\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/api/java/org/openjdk/btrace/metrics/stats/StatsMetric.java",
    "content": "package org.openjdk.btrace.metrics.stats;\n\nimport org.jetbrains.annotations.Nullable;\n\npublic interface StatsMetric {\n  void record(long value);\n  @Nullable StatsSnapshot snapshot();\n  void reset();\n  @Nullable String getName();\n}\n\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/api/java/org/openjdk/btrace/metrics/stats/StatsSnapshot.java",
    "content": "package org.openjdk.btrace.metrics.stats;\n\nimport org.jetbrains.annotations.Nullable;\n\npublic interface StatsSnapshot {\n  @Nullable String getName();\n  long count();\n  long sum();\n  long min();\n  long max();\n  double mean();\n  double stddev();\n}\n\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/impl/java/org/openjdk/btrace/metrics/Metric.java",
    "content": "package org.openjdk.btrace.metrics;\n\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * Base interface for all metrics.\n */\npublic interface Metric {\n  /**\n   * Get the metric name.\n   *\n   * @return metric name\n   */\n  @NotNull\n  String getName();\n\n  /**\n   * Reset the metric to initial state.\n   */\n  void reset();\n}\n\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/impl/java/org/openjdk/btrace/metrics/MetricsServiceImpl.java",
    "content": "package org.openjdk.btrace.metrics;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.openjdk.btrace.core.extensions.Extension;\nimport org.openjdk.btrace.metrics.histogram.HistogramConfig;\nimport org.openjdk.btrace.metrics.histogram.HistogramConfigBuilder;\nimport org.openjdk.btrace.metrics.histogram.HistogramConfigBuilderImpl;\nimport org.openjdk.btrace.metrics.histogram.HistogramConfigImpl;\nimport org.openjdk.btrace.metrics.histogram.HistogramMetric;\nimport org.openjdk.btrace.metrics.histogram.HistogramMetricImpl;\nimport org.openjdk.btrace.metrics.registry.MetricRegistry;\nimport org.openjdk.btrace.metrics.stats.StatsMetric;\nimport org.openjdk.btrace.metrics.stats.StatsMetricImpl;\n\n/**\n * High-performance metrics service built on HdrHistogram.\n *\n * <p>Provides: - Histograms with accurate percentile queries (p50, p95, p99, etc.) - Basic\n * statistics (count, sum, min, max, avg, stddev)\n *\n * <p>Thread-safe and designed for low-latency hot paths.\n */\npublic final class MetricsServiceImpl extends Extension implements MetricsService {\n\n  private final MetricRegistry registry = new MetricRegistry();\n\n  public MetricsServiceImpl() {}\n\n  // ========== Histogram Creation ==========\n\n  @Override\n  public HistogramConfigBuilder newHistogramConfig() {\n    return new HistogramConfigBuilderImpl();\n  }\n\n  /**\n   * Create histogram with default configuration.\n   *\n   * @param name metric name\n   * @return histogram metric\n   */\n  @Nullable\n  public HistogramMetric histogram(@NotNull String name) {\n    // Default: 1ns .. 1h, 3 significant digits\n    return histogram(name, new HistogramConfigImpl(1L, 3_600_000_000_000L, 3));\n  }\n\n  /**\n   * Create histogram with custom configuration.\n   *\n   * @param name metric name\n   * @param config histogram configuration\n   * @return histogram metric\n   */\n  @Nullable\n  public HistogramMetric histogram(@NotNull String name, @NotNull HistogramConfig config) {\n    return registry.getOrCreate(name, null, () -> new HistogramMetricImpl(name, config));\n  }\n\n  /**\n   * Create grouped histogram.\n   *\n   * @param name metric name\n   * @param key grouping key\n   * @return histogram metric\n   */\n  @Nullable\n  public HistogramMetric histogram(@NotNull String name, @NotNull String key) {\n    return registry.getOrCreate(name, key, () -> new HistogramMetricImpl(name, new org.openjdk.btrace.metrics.histogram.HistogramConfigImpl(1L, 3_600_000_000_000L, 3)));\n  }\n\n  // Convenience creators for micros/millis ranges (match prior constants)\n  @Override\n  @Nullable\n  public HistogramMetric histogramMicros(@NotNull String name) {\n    return histogram(name, new HistogramConfigImpl(1L, 60_000_000L, 3));\n  }\n\n  @Override\n  @Nullable\n  public HistogramMetric histogramMicros(@NotNull String name, @NotNull String key) {\n    return registry.getOrCreate(name, key, () -> new HistogramMetricImpl(name, new HistogramConfigImpl(1L, 60_000_000L, 3)));\n  }\n\n  @Override\n  @Nullable\n  public HistogramMetric histogramMillis(@NotNull String name) {\n    return histogram(name, new HistogramConfigImpl(1L, 600_000L, 3));\n  }\n\n  @Override\n  @Nullable\n  public HistogramMetric histogramMillis(@NotNull String name, @NotNull String key) {\n    return registry.getOrCreate(name, key, () -> new HistogramMetricImpl(name, new HistogramConfigImpl(1L, 600_000L, 3)));\n  }\n\n  /**\n   * Create grouped histogram with custom configuration.\n   *\n   * @param name metric name\n   * @param key grouping key\n   * @param config histogram configuration\n   * @return histogram metric\n   */\n  @Nullable\n  public HistogramMetric histogram(@NotNull String name, @NotNull String key, @NotNull HistogramConfig config) {\n    return registry.getOrCreate(name, key, () -> new HistogramMetricImpl(name, config));\n  }\n\n  // ========== Statistics Creation ==========\n\n  /**\n   * Create statistics metric (count/sum/min/max/avg/stddev).\n   *\n   * @param name metric name\n   * @return statistics metric\n   */\n  @Nullable\n  public StatsMetric stats(@NotNull String name) {\n    return registry.getOrCreate(name, null, () -> new StatsMetricImpl(name));\n  }\n\n  /**\n   * Create grouped statistics metric.\n   *\n   * @param name metric name\n   * @param key grouping key\n   * @return statistics metric\n   */\n  @Nullable\n  public StatsMetric stats(@NotNull String name, @NotNull String key) {\n    return registry.getOrCreate(name, key, () -> new org.openjdk.btrace.metrics.stats.StatsMetricImpl(name));\n  }\n\n  // ========== Query Operations ==========\n\n  /**\n   * Reset all metrics.\n   */\n  public void reset() {\n    registry.reset();\n  }\n\n  /**\n   * Clear all metrics.\n   */\n  public void clear() {\n    registry.clear();\n  }\n\n  /**\n   * Get number of registered metrics.\n   *\n   * @return metric count\n   */\n  public int size() {\n    return registry.size();\n  }\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/impl/java/org/openjdk/btrace/metrics/histogram/HistogramConfigBuilderImpl.java",
    "content": "package org.openjdk.btrace.metrics.histogram;\n\npublic final class HistogramConfigBuilderImpl implements HistogramConfigBuilder {\n  private long lowest = 1L;\n  private long highest = 3_600_000_000_000L; // 1 hour in nanos by default\n  private int digits = 3;\n\n  @Override\n  public HistogramConfigBuilder lowestDiscernibleValue(long value) {\n    this.lowest = value;\n    return this;\n  }\n\n  @Override\n  public HistogramConfigBuilder highestTrackableValue(long value) {\n    this.highest = value;\n    return this;\n  }\n\n  @Override\n  public HistogramConfigBuilder significantDigits(int digits) {\n    this.digits = digits;\n    return this;\n  }\n\n  @Override\n  public HistogramConfig build() {\n    return new HistogramConfigImpl(lowest, highest, digits);\n  }\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/impl/java/org/openjdk/btrace/metrics/histogram/HistogramConfigImpl.java",
    "content": "package org.openjdk.btrace.metrics.histogram;\n\npublic final class HistogramConfigImpl implements HistogramConfig {\n  private final long lowestDiscernibleValue;\n  private final long highestTrackableValue;\n  private final int numberOfSignificantValueDigits;\n\n  public HistogramConfigImpl(long lowest, long highest, int digits) {\n    this.lowestDiscernibleValue = lowest;\n    this.highestTrackableValue = highest;\n    this.numberOfSignificantValueDigits = digits;\n  }\n\n  @Override\n  public long getLowestDiscernibleValue() {\n    return lowestDiscernibleValue;\n  }\n\n  @Override\n  public long getHighestTrackableValue() {\n    return highestTrackableValue;\n  }\n\n  @Override\n  public int getNumberOfSignificantValueDigits() {\n    return numberOfSignificantValueDigits;\n  }\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/impl/java/org/openjdk/btrace/metrics/histogram/HistogramMetricImpl.java",
    "content": "package org.openjdk.btrace.metrics.histogram;\n\nimport org.HdrHistogram.Histogram;\nimport org.HdrHistogram.Recorder;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.openjdk.btrace.metrics.Metric;\n\n/**\n * Histogram metric using HdrHistogram for accurate percentiles.\n *\n * <p>Uses Recorder pattern for lock-free writes in hot path.\n */\npublic final class HistogramMetricImpl implements HistogramMetric, Metric {\n\n  private final String name;\n  private final Recorder recorder;\n  private final HistogramConfig config;\n\n  public HistogramMetricImpl(String name, HistogramConfig config) {\n    this.name = name;\n    this.config = config;\n    this.recorder =\n        new Recorder(\n            config.getLowestDiscernibleValue(),\n            config.getHighestTrackableValue(),\n            config.getNumberOfSignificantValueDigits());\n  }\n\n  /**\n   * Record value - ZERO ALLOCATION in hot path.\n   *\n   * @param value value to record\n   */\n  public void record(long value) {\n    recorder.recordValue(value);\n  }\n\n  /**\n   * Record value with count - ZERO ALLOCATION.\n   *\n   * @param value value to record\n   * @param count number of times to record\n   */\n  public void recordValueWithCount(long value, long count) {\n    recorder.recordValueWithCount(value, count);\n  }\n\n  /**\n   * Get snapshot for querying percentiles.\n   *\n   * <p>This allocates a new Histogram via getIntervalHistogram(). Call infrequently (e.g., on\n   * OnEvent).\n   *\n   * @return immutable snapshot\n   */\n  @Nullable\n  public HistogramSnapshot snapshot() {\n    Histogram histogram = recorder.getIntervalHistogram();\n    return new HistogramSnapshotImpl(name, histogram);\n  }\n\n  @Override\n  public void reset() {\n    recorder.reset();\n  }\n\n  @Override\n  @NotNull\n  public String getName() {\n    return name;\n  }\n}\n\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/impl/java/org/openjdk/btrace/metrics/histogram/HistogramSnapshotImpl.java",
    "content": "package org.openjdk.btrace.metrics.histogram;\n\nimport org.HdrHistogram.Histogram;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * Immutable snapshot of histogram for percentile queries.\n */\npublic final class HistogramSnapshotImpl implements HistogramSnapshot {\n\n  private final String name;\n  private final Histogram histogram;\n\n  HistogramSnapshotImpl(String name, Histogram histogram) {\n    this.name = name;\n    this.histogram = histogram;\n  }\n\n  @NotNull\n  public String getName() {\n    return name;\n  }\n\n  // ========== Percentiles ==========\n\n  public long p50() {\n    return histogram.getValueAtPercentile(50.0);\n  }\n\n  public long p75() {\n    return histogram.getValueAtPercentile(75.0);\n  }\n\n  public long p90() {\n    return histogram.getValueAtPercentile(90.0);\n  }\n\n  public long p95() {\n    return histogram.getValueAtPercentile(95.0);\n  }\n\n  public long p99() {\n    return histogram.getValueAtPercentile(99.0);\n  }\n\n  public long p999() {\n    return histogram.getValueAtPercentile(99.9);\n  }\n\n  public long p9999() {\n    return histogram.getValueAtPercentile(99.99);\n  }\n\n  public long percentile(double percentile) {\n    return histogram.getValueAtPercentile(percentile);\n  }\n\n  // ========== Statistics ==========\n\n  public long count() {\n    return histogram.getTotalCount();\n  }\n\n  public long min() {\n    return histogram.getMinValue();\n  }\n\n  public long max() {\n    return histogram.getMaxValue();\n  }\n\n  public double mean() {\n    return histogram.getMean();\n  }\n\n  public double stddev() {\n    return histogram.getStdDeviation();\n  }\n\n  // ========== Access to raw histogram ==========\n\n  public Histogram getHistogram() {\n    return histogram;\n  }\n}\n\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/impl/java/org/openjdk/btrace/metrics/registry/MetricRegistry.java",
    "content": "package org.openjdk.btrace.metrics.registry;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Supplier;\nimport org.openjdk.btrace.metrics.Metric;\n\n/**\n * Thread-safe registry for storing metrics.\n *\n * <p>Supports grouping via String keys.\n */\npublic final class MetricRegistry {\n\n  private final ConcurrentHashMap<String, Metric> metrics = new ConcurrentHashMap<>();\n\n  /**\n   * Get or create a metric.\n   *\n   * @param name metric name\n   * @param key grouping key (null for ungrouped)\n   * @param factory factory to create metric if not present\n   * @param <T> metric type\n   * @return metric instance\n   */\n  @SuppressWarnings(\"unchecked\")\n  public <T extends Metric> T getOrCreate(String name, String key, Supplier<T> factory) {\n    String fullName = makeFullName(name, key);\n    return (T) metrics.computeIfAbsent(fullName, k -> factory.get());\n  }\n\n  /**\n   * Reset all metrics.\n   */\n  public void reset() {\n    for (Metric metric : metrics.values()) {\n      metric.reset();\n    }\n  }\n\n  /**\n   * Get number of registered metrics.\n   *\n   * @return metric count\n   */\n  public int size() {\n    return metrics.size();\n  }\n\n  /**\n   * Clear all metrics.\n   */\n  public void clear() {\n    metrics.clear();\n  }\n\n  private String makeFullName(String name, String key) {\n    if (key == null || key.isEmpty()) {\n      return name;\n    }\n    return name + \":\" + key;\n  }\n}\n\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/impl/java/org/openjdk/btrace/metrics/stats/StatsMetricImpl.java",
    "content": "package org.openjdk.btrace.metrics.stats;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.openjdk.btrace.metrics.Metric;\n\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.atomic.LongAdder;\n\n/**\n * Statistics metric using lock-free atomics.\n *\n * <p>Provides: count, sum, min, max, average, stddev\n *\n * <p>Uses LongAdder for count/sum (better than AtomicLong under contention). Uses AtomicLong for\n * min/max with CAS loop.\n */\npublic final class StatsMetricImpl implements StatsMetric, Metric {\n\n  private final String name;\n  private final LongAdder count = new LongAdder();\n  private final LongAdder sum = new LongAdder();\n  private final LongAdder sumOfSquares = new LongAdder();\n  private final AtomicLong min = new AtomicLong(Long.MAX_VALUE);\n  private final AtomicLong max = new AtomicLong(Long.MIN_VALUE);\n\n  public StatsMetricImpl(String name) {\n    this.name = name;\n  }\n\n  /**\n   * Record value - lock-free.\n   *\n   * @param value value to record\n   */\n  public void record(long value) {\n    count.increment();\n    sum.add(value);\n    sumOfSquares.add(value * value);\n\n    // Update min (CAS loop)\n    long currentMin;\n    do {\n      currentMin = min.get();\n      if (value >= currentMin) {\n        break;\n      }\n    } while (!min.compareAndSet(currentMin, value));\n\n    // Update max (CAS loop)\n    long currentMax;\n    do {\n      currentMax = max.get();\n      if (value <= currentMax) {\n        break;\n      }\n    } while (!max.compareAndSet(currentMax, value));\n  }\n\n  /**\n   * Get immutable snapshot.\n   *\n   * @return snapshot\n   */\n  @Nullable\n  public StatsSnapshot snapshot() {\n    long cnt = count.sum();\n    long sm = sum.sum();\n    long sumSq = sumOfSquares.sum();\n    long mn = min.get();\n    long mx = max.get();\n\n    if (cnt == 0) {\n      return new StatsSnapshotImpl(name, 0, 0, 0, 0, 0, 0);\n    }\n\n    double avg = (double) sm / cnt;\n\n    // Variance = E[X^2] - E[X]^2\n    double variance = ((double) sumSq / cnt) - (avg * avg);\n    double stddev = Math.sqrt(Math.max(0, variance));\n\n    return new StatsSnapshotImpl(name, cnt, sm, mn, mx, avg, stddev);\n  }\n\n  @Override\n  public void reset() {\n    count.reset();\n    sum.reset();\n    sumOfSquares.reset();\n    min.set(Long.MAX_VALUE);\n    max.set(Long.MIN_VALUE);\n  }\n\n  @Override\n  @NotNull\n  public String getName() {\n    return name;\n  }\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/impl/java/org/openjdk/btrace/metrics/stats/StatsSnapshotImpl.java",
    "content": "package org.openjdk.btrace.metrics.stats;\n\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * Immutable snapshot of statistics.\n */\npublic final class StatsSnapshotImpl implements StatsSnapshot {\n\n  private final String name;\n  private final long count;\n  private final long sum;\n  private final long min;\n  private final long max;\n  private final double mean;\n  private final double stddev;\n\n  public StatsSnapshotImpl(\n      String name, long count, long sum, long min, long max, double mean, double stddev) {\n    this.name = name;\n    this.count = count;\n    this.sum = sum;\n    this.min = min;\n    this.max = max;\n    this.mean = mean;\n    this.stddev = stddev;\n  }\n\n  @NotNull\n  public String getName() {\n    return name;\n  }\n\n  public long count() {\n    return count;\n  }\n\n  public long sum() {\n    return sum;\n  }\n\n  public long min() {\n    return min;\n  }\n\n  public long max() {\n    return max;\n  }\n\n  public double mean() {\n    return mean;\n  }\n\n  public double stddev() {\n    return stddev;\n  }\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/test/java/org/openjdk/btrace/metrics/HistogramMetricTest.java",
    "content": "package org.openjdk.btrace.metrics;\n\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.metrics.histogram.HistogramConfigImpl;\nimport org.openjdk.btrace.metrics.histogram.HistogramMetric;\nimport org.openjdk.btrace.metrics.histogram.HistogramMetricImpl;\nimport org.openjdk.btrace.metrics.histogram.HistogramSnapshot;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass HistogramMetricTest {\n  @Test\n  void recordsAndSnapshots() {\n    HistogramMetric m = new HistogramMetricImpl(\"h\", new HistogramConfigImpl(1L, 600_000L, 3));\n    m.record(10);\n    m.record(20);\n    HistogramSnapshot snap = m.snapshot();\n    assertEquals(\"h\", snap.getName());\n    assertTrue(snap.count() >= 2);\n    assertTrue(snap.max() >= 20);\n  }\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-metrics/src/test/java/org/openjdk/btrace/metrics/StatsMetricTest.java",
    "content": "package org.openjdk.btrace.metrics;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.metrics.stats.StatsMetric;\nimport org.openjdk.btrace.metrics.stats.StatsSnapshot;\n\nclass StatsMetricTest {\n  @Test\n  void accumulatesAndSnapshots() {\n    StatsMetric m = new org.openjdk.btrace.metrics.stats.StatsMetricImpl(\"s\");\n    m.record(1);\n    m.record(3);\n    StatsSnapshot snap = m.snapshot();\n    assertEquals(\"s\", snap.getName());\n    assertEquals(2, snap.count());\n    assertEquals(4, snap.sum());\n    assertEquals(1, snap.min());\n    assertEquals(3, snap.max());\n  }\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-statsd/build.gradle",
    "content": "plugins {\n    id 'org.openjdk.btrace.extension'\n    alias(libs.plugins.shadow)\n}\n\njava {\n    sourceCompatibility = 8\n    targetCompatibility = 8\n}\n\ncompileJava {\n    javaCompiler = javaToolchains.compilerFor {\n        languageVersion.set(JavaLanguageVersion.of(11))\n    }\n}\n\nbtraceExtension {\n    id = 'btrace-statsd'\n    name = 'BTrace StatsD'\n    description = 'StatsD metrics client for BTrace'\n    services = ['org.openjdk.btrace.statsd.Statsd']\n}\n\ndependencies {\n    apiCompileOnly project(':btrace-core')\n    implImplementation project(':btrace-core')\n    implementation libs.slf4j\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-statsd/src/api/java/org/openjdk/btrace/statsd/Statsd.java",
    "content": "package org.openjdk.btrace.statsd;\n\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.core.extensions.ServiceDescriptor;\n\n/** API for StatsD metrics client. */\n@ServiceDescriptor(permissions = { Permission.NETWORK })\npublic interface Statsd {\n  void increment(String name);\n  void increment(String name, String tags);\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-statsd/src/api/java/org/openjdk/btrace/statsd/package-info.java",
    "content": "@ExtensionDescriptor(\n    name = \"btrace-statsd\",\n    version = \"1.0\",\n    description = \"StatsD metrics APIs\",\n    permissions = { Permission.NETWORK }\n)\npackage org.openjdk.btrace.statsd;\n\nimport org.openjdk.btrace.core.extensions.ExtensionDescriptor;\nimport org.openjdk.btrace.core.extensions.Permission;\n\n"
  },
  {
    "path": "btrace-extensions/btrace-statsd/src/impl/java/org/openjdk/btrace/statsd/StatsdImpl.java",
    "content": "package org.openjdk.btrace.statsd;\n\nimport java.net.DatagramPacket;\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\nimport java.nio.charset.StandardCharsets;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.core.extensions.Extension;\nimport org.openjdk.btrace.core.extensions.Permission;\n\npublic final class StatsdImpl extends Extension implements Statsd {\n  @Override\n  public void increment(String name) {\n    increment(name, null);\n  }\n\n  @Override\n  public void increment(String name, String tags) {\n    try {\n      StringBuilder sb = new StringBuilder();\n      sb.append(name).append(\":1|c\");\n      if (tags != null && !tags.isEmpty()) {\n        sb.append(\"|#\").append(tags);\n      }\n      byte[] data = sb.toString().getBytes(StandardCharsets.US_ASCII);\n      DatagramPacket pkt = new DatagramPacket(data, data.length);\n      pkt.setAddress(InetAddress.getByName(SharedSettings.GLOBAL.getStatsdHost()));\n      pkt.setPort(SharedSettings.GLOBAL.getStatsdPort());\n      try (DatagramSocket socket = new DatagramSocket()) {\n        socket.send(pkt);\n      }\n    } catch (Throwable ignore) {\n      // Best-effort, ignore errors in script path\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-utils/build.gradle",
    "content": "plugins {\n    id 'org.openjdk.btrace.extension'\n    alias(libs.plugins.shadow)\n}\n\njava {\n    sourceCompatibility = 8\n    targetCompatibility = 8\n}\n\ncompileJava {\n    javaCompiler = javaToolchains.compilerFor {\n        languageVersion.set(JavaLanguageVersion.of(11))\n    }\n}\n\nbtraceExtension {\n    id = 'btrace-utils'\n    name = 'BTrace Utilities'\n    description = 'Utility services for BTrace scripts (eg. printer)'\n    services = ['org.openjdk.btrace.utils.PrinterService']\n}\n\ndependencies {\n    // API dependencies (minimal) - no legacy services API\n    apiCompileOnly project(':btrace-core')\n    implImplementation project(':btrace-core')\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-utils/src/api/java/org/openjdk/btrace/utils/PrinterService.java",
    "content": "package org.openjdk.btrace.utils;\n\nimport org.openjdk.btrace.core.extensions.ServiceDescriptor;\n\n/**\n * Simple printer service API for BTrace scripts.\n */\n@ServiceDescriptor\npublic interface PrinterService {\n  void print(String s);\n  void println(String s);\n  void println();\n}\n"
  },
  {
    "path": "btrace-extensions/btrace-utils/src/api/java/org/openjdk/btrace/utils/package-info.java",
    "content": "@ExtensionDescriptor(\n    name = \"btrace-utils\",\n    version = \"1.0\",\n    description = \"Utility helper APIs for BTrace scripts\"\n)\npackage org.openjdk.btrace.utils;\n\nimport org.openjdk.btrace.core.extensions.ExtensionDescriptor;\n\n"
  },
  {
    "path": "btrace-extensions/btrace-utils/src/impl/java/org/openjdk/btrace/utils/PrinterServiceImpl.java",
    "content": "package org.openjdk.btrace.utils;\n\nimport org.openjdk.btrace.core.extensions.Extension;\n\npublic final class PrinterServiceImpl extends Extension implements PrinterService {\n  private static final String NL = System.getProperty(\"line.separator\");\n\n  @Override\n  public void print(String s) {\n    if (s != null) {\n      getContext().send(s);\n    }\n  }\n\n  @Override\n  public void println(String s) {\n    print(s + NL);\n  }\n\n  @Override\n  public void println() {\n    print(NL);\n  }\n\n  @Override\n  public void close() {\n    if (getContext().getArgs().containsKey(\"extensionCloseTest\")) {\n      getContext().send(\"extension close: btrace-utils\");\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-extensions/build.gradle",
    "content": "plugins {\n    id 'base'\n}\n\n// Aggregate task to build API JARs of all contained extensions\ntasks.register('buildExtensionsApi') {\n    group = 'build'\n    description = 'Build API JARs for all extensions in this composite project.'\n}\n\n// Wire all child projects that expose a buildApiJar task\ngradle.projectsEvaluated {\n    tasks.named('buildExtensionsApi').configure {\n        subprojects.each { sp ->\n            def apiTask = sp.tasks.findByName('buildApiJar')\n            if (apiTask != null) {\n                dependsOn(apiTask)\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "btrace-gradle-plugin/README.md",
    "content": "BTrace Gradle Extension Plugin\n\nOverview\n- Gradle plugin to build and package BTrace extensions with sane defaults.\n- Scans implementation bytecode to infer minimal required permissions and writes them into the API JAR manifest.\n- Produces three artifacts: API JAR (`classifier=api`), Impl JAR (`classifier=impl`, shadowed), and a distributable ZIP (`classifier=extension`).\n\nApply The Plugin\n```\nplugins {\n  id(\"org.openjdk.btrace.extension\") version \"${btraceVersion}\"\n}\n\nrepositories {\n  mavenCentral()\n  mavenLocal() // if you published locally for testing\n}\n```\n\nProject Layout\n- `src/api/java`, `src/api/resources`: public API package visible to BTrace scripts and the agent (ends up on bootstrap).\n- `src/impl/java`, `src/impl/resources`: implementation package shadowed and isolated behind the API manifest.\n\nDSL (extension `btraceExtension`)\n```\nbtraceExtension {\n  id = \"com.example.myext\"         // required: globally unique extension ID\n  name = \"My Extension\"            // optional\n  description = \"Does things\"      // optional\n\n  // Optional: omit to auto-detect from @ServiceDescriptor annotations in API classes\n  services = [\n    \"com.example.myext.api.MyService\"\n  ]\n  requiresExtensions = [\n    // other extension IDs if you depend on them\n  ]\n\n  shadedPackages = [\n    // from : to (relocations applied to impl JAR)\n    \"com.example.dep\" : \"com.example.myext.shaded.dep\"\n  ]\n\n  // Permissions\n  scanPermissions = true           // default: scan impl JAR + classpath\n  requiredPermissions = [          // optional overrides/additions\n    // \"NETWORK\", \"FILE_READ\", \"FILE_WRITE\", \"THREADS\", \"EXEC\", \"NATIVE\",\n    // \"REFLECTION\", \"CLASSLOADER\", \"SYSTEM_PROPS\", \"THREAD_INFO\", \"MEMORY_INFO\", \"JFR_EVENTS\"\n  ]\n}\n```\n\nOutputs\n- API JAR: `build/libs/<name>-<version>-api.jar` with manifest entries:\n  - `BTrace-Extension-Id`, `BTrace-Extension-Services`, `BTrace-Extension-Permissions`, `BTrace-Extension-Requires`, `BTrace-Shaded-Packages`, `BTrace-Extension-Impl`.\n- Impl JAR: `build/libs/<name>-<version>-impl.jar` (shadowed, minimized) containing impl classes and shaded deps.\n- Distribution ZIP: `build/distributions/<name>-<version>-extension.zip` bundling both JARs.\n\nTasks\n- `buildApiJar`: builds the API JAR and writes extension metadata into the manifest.\n- `shadowJar`: builds the impl JAR from `impl` source set, applying relocations and minimization.\n- `packageExtension`: bundles API + Impl into a ZIP.\n\nTips\n- Keep API small and stable; only types used by BTrace scripts or injected services belong in API.\n- Put all runtime dependencies into `impl` and shade them to avoid leaking into the target JVM.\n- If scanning is too conservative, add `requiredPermissions` explicitly.\n\nPackage-level metadata (optional)\n- You may add `@ExtensionDescriptor` to `package-info.java` in your API package to document name/version/description.\n- The plugin relies on manifest attributes as the canonical metadata; `@ExtensionDescriptor` is for documentation only.\n\nLocal Publish For Testing\n```\n./gradlew :btrace-gradle-plugin:publishToMavenLocal\n```\nThen in your extension project, add `mavenLocal()` to repositories or pluginManagement and use the same plugin version.\n  // Lints\n  apiCtorSeverity = 'error'        // 'off' | 'warn' | 'error' (default: 'error'). Warn/fail on public API classes with public constructors.\n"
  },
  {
    "path": "btrace-gradle-plugin/build.gradle",
    "content": "plugins {\n    id 'groovy'\n    id 'java-gradle-plugin'\n    id 'maven-publish'\n}\n\njava {\n    toolchain {\n        languageVersion = JavaLanguageVersion.of(11)\n    }\n}\n\ngroup = project.findProperty('GROUP') ?: (rootProject.group ?: 'org.openjdk.btrace')\nversion = rootProject.version\n\nrepositories {\n    gradlePluginPortal()\n    mavenCentral()\n}\n\ndependencies {\n    implementation gradleApi()\n    implementation localGroovy()\n    // Match versions commonly cached in this repository to avoid extra fetches\n    implementation 'org.ow2.asm:asm:9.9.1'\n    implementation 'org.ow2.asm:asm-tree:9.9.1'\n}\n\ngradlePlugin {\n    plugins {\n        btraceExtension {\n            id = 'org.openjdk.btrace.extension'\n            implementationClass = 'org.openjdk.btrace.gradle.BTraceExtensionPlugin'\n            displayName = 'BTrace Extension Plugin'\n            description = 'Builds and packages BTrace extensions, scanning permissions and wiring manifests.'\n        }\n    }\n}\n\npublishing {\n    publications {\n        // java-gradle-plugin will add pluginMaven and marker publications automatically.\n        // This block allows publishing to local/remote Maven repositories.\n        withType(MavenPublication) {\n            pom {\n                name = 'BTrace Gradle Extension Plugin'\n                description = 'Gradle plugin for building BTrace extensions'\n                url = 'https://github.com/btraceio/btrace'\n                licenses {\n                    license {\n                        name = 'GPL-2.0 with Classpath Exception'\n                        url = 'https://openjdk.org/legal/gplv2+ce.html'\n                    }\n                }\n                developers {\n                    developer {\n                        id = 'btrace'\n                        name = 'BTrace Project'\n                        url = 'https://github.com/btraceio'\n                    }\n                }\n                scm {\n                    url = 'https://github.com/btraceio/btrace'\n                    connection = 'scm:git:https://github.com/btraceio/btrace.git'\n                    developerConnection = 'scm:git:ssh://git@github.com:btraceio/btrace.git'\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-gradle-plugin/src/main/groovy/org/openjdk/btrace/gradle/BTraceExtensionPlugin.groovy",
    "content": "package org.openjdk.btrace.gradle\n\nimport org.gradle.api.Plugin\nimport org.gradle.api.Project\nimport org.gradle.api.GradleException\nimport org.gradle.api.tasks.bundling.Jar\nimport org.gradle.api.tasks.bundling.Zip\nimport org.gradle.api.tasks.javadoc.Javadoc\nimport org.gradle.api.tasks.compile.JavaCompile\nimport org.gradle.api.tasks.Copy\nimport org.gradle.api.file.DuplicatesStrategy\nimport java.lang.reflect.Modifier\nimport java.net.URLClassLoader\nimport org.objectweb.asm.ClassReader\nimport org.objectweb.asm.Type\nimport org.objectweb.asm.tree.AnnotationNode\nimport org.objectweb.asm.tree.ClassNode\nimport org.objectweb.asm.tree.MethodNode\nimport org.objectweb.asm.tree.TypeAnnotationNode\nimport org.objectweb.asm.TypeReference\nimport org.objectweb.asm.signature.SignatureReader\nimport org.objectweb.asm.signature.SignatureVisitor\nimport org.objectweb.asm.Opcodes\n\nclass BTraceExtensionPlugin implements Plugin<Project> {\n\n    @Override\n    void apply(Project project) {\n        // Apply required plugins\n        project.plugins.apply('java')\n        // Optionally apply maven-publish when available so we can publish artifacts easily\n        try { project.plugins.apply('maven-publish') } catch (Throwable ignore) {}\n\n        // Try to ensure Shadow is available; if resolution is blocked, we will emit a clear\n        // error later with guidance. This is best-effort and safe when already applied.\n        try {\n            if (!project.pluginManager.hasPlugin('com.github.johnrengelman.shadow')) {\n                // Respect opt-out\n                def ext = project.extensions.findByType(BTraceExtensionMetadata)\n                boolean shouldAutoApply = (ext == null) ? true : (ext.autoApplyShadow != false)\n                if (shouldAutoApply) {\n                    project.logger.lifecycle(\"[BTRACE-EXT] Applying Shadow plugin automatically (com.github.johnrengelman.shadow) for ${project.path}\")\n                    project.pluginManager.apply('com.github.johnrengelman.shadow')\n                } else {\n                    project.logger.lifecycle(\"[BTRACE-EXT] Shadow auto-apply disabled (btraceExtension.autoApplyShadow=false) for ${project.path}\")\n                }\n            }\n        } catch (Throwable t) {\n            project.logger.warn(\"[BTRACE-EXT] Unable to auto-apply Shadow plugin: ${t.message}. Apply it explicitly via plugins { id 'com.github.johnrengelman.shadow' } or alias(libs.plugins.shadow), or set btraceExtension.autoApplyShadow=true.\")\n        }\n\n        // Create extension for metadata\n        def extension = project.extensions.create('btraceExtension', BTraceExtensionMetadata)\n        extension.version = project.version\n\n        // Configure source sets\n        project.sourceSets {\n            api {\n                java.srcDir 'src/api/java'\n                resources.srcDir 'src/api/resources'\n            }\n            impl {\n                java.srcDir 'src/impl/java'\n                resources.srcDir 'src/impl/resources'\n                compileClasspath += api.output\n                runtimeClasspath += api.output\n            }\n        }\n\n        // Configure dependency configurations\n        project.configurations {\n            apiImplementation.extendsFrom implementation\n            apiCompileOnly.extendsFrom compileOnly\n\n            implImplementation.extendsFrom implementation\n            implImplementation.extendsFrom apiImplementation\n            implCompileOnly.extendsFrom compileOnly\n        }\n\n        // Configure duplicate handling for resource tasks\n        project.tasks.withType(Copy).configureEach {\n            duplicatesStrategy = DuplicatesStrategy.EXCLUDE\n        }\n\n        // Task: Build API JAR\n        def buildApiJar = project.tasks.register('buildApiJar', Jar) {\n            from project.sourceSets.api.output\n            archiveClassifier = 'api'\n            archiveBaseName = project.name\n        }\n\n        // Task: Validate API service interfaces (practical subset of rules)\n        def validateServiceApis = project.tasks.register('validateServiceApis') {\n            dependsOn project.tasks.named('compileApiJava')\n            doLast {\n                // Lint: API classes with public constructors (discouraged; use service-provided builders)\n                def apiCtorIssues = [] as List<String>\n                project.sourceSets.api.output.classesDirs.files.each { File dir ->\n                    if (!dir.exists()) return\n                    dir.eachFileRecurse { f ->\n                        if (!f.name.endsWith('.class')) return\n                        def rel = dir.toPath().relativize(f.toPath()).toString()\n                        def internalName = rel.replace(File.separatorChar, (char)'/').replaceAll(/\\.class$/, '')\n                        if (internalName.endsWith('package-info') || internalName.endsWith('module-info')) return\n                        FileInputStream is = new FileInputStream(f)\n                        byte[] bytes\n                        try { bytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                        def cr = new ClassReader(bytes)\n                        def cn = new ClassNode()\n                        cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                        int acc = cn.access\n                        boolean isInterface = (acc & Opcodes.ACC_INTERFACE) != 0\n                        boolean isAnnotation = (acc & Opcodes.ACC_ANNOTATION) != 0\n                        boolean isPublic = (acc & Opcodes.ACC_PUBLIC) != 0\n                        if (isPublic && !isInterface && !isAnnotation) {\n                            boolean hasPublicCtor = false\n                            (cn.methods ?: []).each { MethodNode mn ->\n                                if (\"<init>\".equals(mn.name) && (mn.access & Opcodes.ACC_PUBLIC) != 0) {\n                                    hasPublicCtor = true\n                                }\n                            }\n                            if (hasPublicCtor) {\n                                apiCtorIssues << internalName.replace('/', '.')\n                            }\n                        }\n                    }\n                }\n                if (!apiCtorIssues.isEmpty()) {\n                    def sev = (project.extensions.findByType(BTraceExtensionMetadata)?.apiCtorSeverity ?: 'warn')\n                    def msg = \"[BTRACE-EXT] API classes with public constructors (avoid 'new' in probes; provide service builders/factories instead): ${apiCtorIssues}\"\n                    if (\"error\".equalsIgnoreCase(sev)) {\n                        throw new GradleException(msg)\n                    } else if (!\"off\".equalsIgnoreCase(sev)) {\n                        project.logger.warn(msg)\n                    }\n                }\n                // Enforce: at most one package-level @ExtensionDescriptor across the project\n                def extDescDesc = 'Lorg/openjdk/btrace/core/extensions/ExtensionDescriptor;'\n                int extDescCount = 0\n                def scanForPkgDescriptors = { File classesDir ->\n                    if (classesDir == null || !classesDir.exists()) return\n                    classesDir.eachFileRecurse { f ->\n                        if (!f.name.endsWith('.class')) return\n                        if (!f.name.equals('package-info.class')) return\n                        FileInputStream is = new FileInputStream(f)\n                        byte[] bytes\n                        try { bytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                        def cr = new ClassReader(bytes)\n                        def cn = new ClassNode()\n                        cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                        boolean has = false\n                        (cn.visibleAnnotations ?: []).each { has |= (it.desc == extDescDesc) }\n                        (cn.invisibleAnnotations ?: []).each { has |= (it.desc == extDescDesc) }\n                        if (has) extDescCount++\n                    }\n                }\n                project.sourceSets.api.output.classesDirs.files.each { scanForPkgDescriptors(it) }\n                try { project.sourceSets.impl.output.classesDirs.files.each { scanForPkgDescriptors(it) } } catch (Throwable ignore) {}\n                if (extDescCount > 1) {\n                    throw new GradleException(\"[BTRACE-EXT] Found ${extDescCount} package-level @ExtensionDescriptor annotations. Only one is allowed per extension project (place it in API package-info.java).\")\n                }\n\n                // Prefer explicitly configured services; otherwise, detect via @ServiceDescriptor annotations\n                def services = extension.services as List<String>\n                if (!services || services.isEmpty()) {\n                    def detected = new LinkedHashSet<String>()\n                    project.sourceSets.api.output.classesDirs.files.each { File dir ->\n                        if (!dir.exists()) return\n                        dir.eachFileRecurse { f ->\n                            if (!f.name.endsWith('.class')) return\n                            def rel = dir.toPath().relativize(f.toPath()).toString()\n                            def fq = rel.replace(File.separatorChar, (char)'.').replaceAll(/\\.class$/, '')\n                            FileInputStream is = new FileInputStream(f)\n                            byte[] bytes\n                            try { bytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                            def cr = new ClassReader(bytes)\n                            def cn = new ClassNode()\n                            cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                            def isInterface = (cn.access & Opcodes.ACC_INTERFACE) != 0\n                            def hasMarker = false\n                            (cn.visibleAnnotations ?: []).each { hasMarker |= (it.desc == 'Lorg/openjdk/btrace/core/extensions/ServiceDescriptor;') }\n                            (cn.invisibleAnnotations ?: []).each { hasMarker |= (it.desc == 'Lorg/openjdk/btrace/core/extensions/ServiceDescriptor;') }\n                            if (hasMarker && isInterface) detected.add(fq)\n                        }\n                    }\n                    services = detected as List<String>\n                    if (!services.isEmpty()) {\n                        project.logger.lifecycle(\"[BTRACE-EXT] detected services via @ServiceDescriptor: ${services}\")\n                    } else {\n                        project.logger.warn('[BTRACE-EXT] No services declared or detected; skipping validation')\n                        return\n                    }\n                }\n                def cp = new LinkedHashSet<File>()\n                cp.addAll(project.sourceSets.api.output.classesDirs.files)\n                try { cp.addAll(project.sourceSets.api.compileClasspath.files) } catch (Throwable ignore) {}\n                URLClassLoader cl = new URLClassLoader(cp.collect { it.toURI().toURL() } as URL[], (ClassLoader) null)\n                def errors = []\n                def warnings = []\n                def perService = new LinkedHashMap<String, List<String>>()\n                def perServiceWarn = new LinkedHashMap<String, List<String>>()\n\n                // Build set of impl class names for purity checks\n                def implClassNames = new HashSet<String>()\n                project.sourceSets.impl.output.classesDirs.files.each { File dir ->\n                    if (!dir.exists()) return\n                    dir.eachFileRecurse { f ->\n                        if (f.name.endsWith('.class')) {\n                            def rel = dir.toPath().relativize(f.toPath()).toString()\n                            implClassNames.add(rel.replace(File.separatorChar, (char)'.').replaceAll(/\\.class$/, ''))\n                        }\n                    }\n                }\n                // Build set of api class names to avoid false positives when impl and api share packages/types\n                def apiClassNames = new HashSet<String>()\n                project.sourceSets.api.output.classesDirs.files.each { File dir ->\n                    if (!dir.exists()) return\n                    dir.eachFileRecurse { f ->\n                        if (f.name.endsWith('.class')) {\n                            def rel = dir.toPath().relativize(f.toPath()).toString()\n                            apiClassNames.add(rel.replace(File.separatorChar, (char)'.').replaceAll(/\\.class$/, ''))\n                        }\n                    }\n                }\n\n                // Nullability annotation descriptors (configurable)\n                def toDesc = { String fqcn -> 'L' + fqcn.replace('.', '/') + ';' }\n                def defaultNullable = ['javax.annotation.Nullable','org.jspecify.annotations.Nullable','org.jetbrains.annotations.Nullable','jakarta.annotation.Nullable']\n                def defaultNonnull = ['javax.annotation.Nonnull','org.jspecify.annotations.NonNull','org.jetbrains.annotations.NotNull','jakarta.annotation.Nonnull']\n                def NULLABLE = ((extension.nullableAnnotations ?: defaultNullable).collect(toDesc)) as Set\n                def NONNULL = ((extension.nonnullAnnotations ?: defaultNonnull).collect(toDesc)) as Set\n                int countW020 = 0\n                int countW021 = 0\n                int count022  = 0\n\n                services.each { String fqcn ->\n                    try {\n                        Class<?> c = Class.forName(fqcn, false, cl)\n                        def errs = perService.computeIfAbsent(fqcn) { [] }\n                        if (!c.isInterface()) {\n                            def msg = \"Service '${fqcn}' must be a public top-level interface; found ${c.modifiers.toString()}\\n  Fix: Convert to a public top-level interface.\"\n                            errors << msg; errs << msg\n                        }\n                        if (!Modifier.isPublic(c.getModifiers())) {\n                            def msg = \"Service '${fqcn}' must be public\\n  Fix: Add 'public' modifier.\"\n                            errors << msg; errs << msg\n                        }\n                        if (c.getDeclaringClass() != null) {\n                            def msg = \"Service '${fqcn}' must be top-level (not inner)\\n  Fix: Move to a top-level interface.\"\n                            errors << msg; errs << msg\n                        }\n                        // No fields except constants (public static final primitives/Strings)\n                        c.getDeclaredFields().each { f ->\n                            int m = f.modifiers\n                            if (!(Modifier.isPublic(m) && Modifier.isStatic(m) && Modifier.isFinal(m))) {\n                                def msg = \"Field '${fqcn}.${f.name}' not allowed; only compile-time constants permitted\\n  Fix: Remove mutable/stateful fields from interfaces.\"\n                                errors << msg; errs << msg\n                            }\n                        }\n                        // Prepare ASM method annotation info for this class\n                        def resName = fqcn.replace('.', '/') + '.class'\n                        def is = cl.getResourceAsStream(resName)\n                        if (is == null) {\n                            def msg = \"Declared service '${fqcn}' not found in API output; ensure it is compiled in 'api' source set\\n  Fix: Add interface to src/api/java and to btraceExtension.services.\"\n                            errors << msg; perService.computeIfAbsent(fqcn) { [] } << msg\n                            return\n                        }\n                        byte[] classBytes\n                        try { classBytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                        def cr = new ClassReader(classBytes)\n                        def cn = new ClassNode()\n                        cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                        def methodAnnoInfo = [:] // key=name+desc -> [retNullable, retNonNull, paramAnno: idx->[nullable, nonnull]]\n                        def permAnnoSet = new HashSet<String>()\n                        // Collect ServiceDescriptor.permissions\n                        def collectServicePerms = { AnnotationNode an ->\n                            if (an == null) return\n                            if (an.desc == 'Lorg/openjdk/btrace/core/extensions/ServiceDescriptor;') {\n                                def vals = an.values ?: []\n                                for (int i = 0; i < vals.size(); i += 2) {\n                                    if (vals[i] == 'permissions') {\n                                        def arr = vals[i+1] as List\n                                        arr?.each { ev ->\n                                            if (ev instanceof List && ev.size() >= 2) {\n                                                permAnnoSet.add(String.valueOf(ev[1]))\n                                            }\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                        (cn.visibleAnnotations ?: []).each(collectServicePerms)\n                        (cn.invisibleAnnotations ?: []).each(collectServicePerms)\n                        cn.methods.each { MethodNode mn ->\n                            def key = mn.name + mn.desc\n                            def info = [retNullable:false, retNonNull:false, paramAnno:[:]]\n                            (mn.visibleAnnotations ?: []).each { AnnotationNode an ->\n                                if (NULLABLE.contains(an.desc)) info.retNullable = true\n                                if (NONNULL.contains(an.desc)) info.retNonNull = true\n                                collectServicePerms(an)\n                            }\n                            (mn.invisibleAnnotations ?: []).each { AnnotationNode an ->\n                                if (NULLABLE.contains(an.desc)) info.retNullable = true\n                                if (NONNULL.contains(an.desc)) info.retNonNull = true\n                                collectServicePerms(an)\n                            }\n                            (mn.visibleTypeAnnotations ?: []).each { TypeAnnotationNode tan ->\n                                def tr = new TypeReference(tan.typeRef)\n                                if (tr.sort == TypeReference.METHOD_RETURN) {\n                                    if (NULLABLE.contains(tan.desc)) info.retNullable = true\n                                    if (NONNULL.contains(tan.desc)) info.retNonNull = true\n                                } else if (tr.sort == TypeReference.METHOD_FORMAL_PARAMETER) {\n                                    int pidx = tr.formalParameterIndex\n                                    def pa = info.paramAnno.computeIfAbsent(pidx) { [nullable:false, nonnull:false] }\n                                    if (NULLABLE.contains(tan.desc)) pa.nullable = true\n                                    if (NONNULL.contains(tan.desc)) pa.nonnull = true\n                                }\n                            }\n                            (mn.invisibleTypeAnnotations ?: []).each { TypeAnnotationNode tan ->\n                                def tr = new TypeReference(tan.typeRef)\n                                if (tr.sort == TypeReference.METHOD_RETURN) {\n                                    if (NULLABLE.contains(tan.desc)) info.retNullable = true\n                                    if (NONNULL.contains(tan.desc)) info.retNonNull = true\n                                } else if (tr.sort == TypeReference.METHOD_FORMAL_PARAMETER) {\n                                    int pidx = tr.formalParameterIndex\n                                    def pa = info.paramAnno.computeIfAbsent(pidx) { [nullable:false, nonnull:false] }\n                                    if (NULLABLE.contains(tan.desc)) pa.nullable = true\n                                    if (NONNULL.contains(tan.desc)) pa.nonnull = true\n                                }\n                            }\n                            // Parameter annotations (non type-use)\n                            int paramCount = (mn.visibleParameterAnnotations ?: new List[0]).length\n                            for (int i = 0; i < paramCount; i++) {\n                                def lst = mn.visibleParameterAnnotations[i]\n                                if (lst == null) continue\n                                def pa = info.paramAnno.computeIfAbsent(i) { [nullable:false, nonnull:false] }\n                                lst.each { AnnotationNode an ->\n                                    if (NULLABLE.contains(an.desc)) pa.nullable = true\n                                    if (NONNULL.contains(an.desc)) pa.nonnull = true\n                                }\n                            }\n                            paramCount = (mn.invisibleParameterAnnotations ?: new List[0]).length\n                            for (int i = 0; i < paramCount; i++) {\n                                def lst = mn.invisibleParameterAnnotations[i]\n                                if (lst == null) continue\n                                def pa = info.paramAnno.computeIfAbsent(i) { [nullable:false, nonnull:false] }\n                                lst.each { AnnotationNode an ->\n                                    if (NULLABLE.contains(an.desc)) pa.nullable = true\n                                    if (NONNULL.contains(an.desc)) pa.nonnull = true\n                                }\n                            }\n                            methodAnnoInfo[key] = info\n                        }\n\n                        // Permission alignment: if permissions annotated in API, ensure either scanning is on\n                        // or declared requiredPermissions include at least those.\n                        if (!permAnnoSet.isEmpty()) {\n                            if (!extension.scanPermissions) {\n                                def declared = (extension.requiredPermissions ?: [])*.toString()*.toUpperCase(java.util.Locale.ROOT) as Set\n                                def missing = permAnnoSet.findAll { !declared.contains(String.valueOf(it).toUpperCase(java.util.Locale.ROOT)) }\n                                if (!missing.isEmpty()) {\n                                    errors << \"Service '${fqcn}' requires permissions ${missing} not covered by plugin requiredPermissions; enable scanPermissions or add them.\"\n                                }\n                            }\n                        }\n\n                        // Methods: no default methods, no checked throws, no forbidden signature types\n                        c.getMethods().each { m ->\n                            // Only methods declared on this interface (avoid Object methods)\n                            if (m.declaringClass != c) return\n                            if (m.isDefault()) {\n                                def msg = \"Default method '${fqcn}#${m.name}' not allowed (Java 8 shim-compat)\\n  Fix: Move behavior to implementation; keep API pure.\"\n                                errors << msg; errs << msg\n                            }\n                            // Checked exceptions\n                            m.exceptionTypes.each { ex ->\n                                if (!(RuntimeException.isAssignableFrom(ex) || Error.isAssignableFrom(ex))) {\n                                    def msg = \"Method '${fqcn}#${m.name}' declares checked exception: ${ex.name}\\n  Fix: Remove checked exceptions from API signatures.\"\n                                    errors << msg; errs << msg\n                                }\n                            }\n                            // Forbidden signature packages\n                            def forbid = [\n                                'java.io.', 'java.net.', 'java.nio.channels.', 'java.lang.reflect.'\n                            ]\n                            def allTypes = []\n                            allTypes << m.returnType\n                            allTypes.addAll(m.parameterTypes)\n                            allTypes.each { t ->\n                                String n = t.name\n                                if (forbid.any { n.startsWith(it) }) {\n                                    def msg = \"Method '${fqcn}#${m.name}' uses forbidden type in signature: ${n}\\n  Fix: Restrict signatures to JDK types and API interfaces.\"\n                                    errors << msg; errs << msg\n                                }\n                                if (implClassNames.contains(n)) {\n                                    def msg = \"API surface leaks implementation type in signature: ${n}\\n  Fix: Do not expose implementation types from src/impl in API signatures.\"\n                                    errors << msg; errs << msg\n                                }\n                            }\n\n                            // Nullability + shimability\n                            def md = Type.getMethodDescriptor(Type.getType(m.returnType), m.parameterTypes.collect { Type.getType(it) } as Type[])\n                            def key = m.name + md\n                            def info = methodAnnoInfo.get(key) ?: [retNullable:false, retNonNull:false, paramAnno:[:]]\n                            // Return nullability: only relevant for reference types (not void/primitives)\n                            if (m.returnType != Void.TYPE && !m.returnType.isPrimitive()) {\n                                if (!(info.retNullable || info.retNonNull)) {\n                                    def msgWarn = \"Missing nullability on return of '${fqcn}#${m.name}'\\n  Fix: Annotate with @NonNull or @Nullable.\"\n                                    warnings << msgWarn; perServiceWarn.computeIfAbsent(fqcn) { [] } << msgWarn\n                                    countW020++\n                                }\n                                // Shimability: if return is interface, require @Nullable unless configured otherwise\n                                if (m.returnType.isInterface() && !info.retNullable) {\n                                    def msg22 = \"Return type '${m.returnType.name}' of '${fqcn}#${m.name}' must be @Nullable for shim compatibility\\n  Fix: Mark interface returns @Nullable or provide a documented default.\"\n                                    if ((extension.shimabilitySeverity ?: 'error').equalsIgnoreCase('warn')) {\n                                        warnings << msg22; perServiceWarn.computeIfAbsent(fqcn) { [] } << msg22\n                                    } else {\n                                        errors << msg22; errs << msg22\n                                    }\n                                    count022++\n                                }\n                            }\n                            // Parameter nullability: recommend but do not enforce by default\n                            m.parameterTypes.eachWithIndex { pt, idx ->\n                                if (!(pt.isPrimitive())) {\n                                    def pinfo = info.paramAnno.get(idx) ?: [nullable:false, nonnull:false]\n                                    if (!(pinfo.nullable || pinfo.nonnull)) {\n                                        def msg21 = \"Missing nullability on parameter ${idx} of '${fqcn}#${m.name}'\\n  Fix: Annotate each parameter with @NonNull or @Nullable.\"\n                                        if ((extension.nullabilitySeverity ?: 'warn').equalsIgnoreCase('error')) {\n                                            def emsg = \"Missing nullability on parameter ${idx} of '${fqcn}#${m.name}'\\n  Fix: Annotate each parameter with @NonNull or @Nullable.\"\n                                            errors << emsg; errs << emsg\n                                        } else if (!'off'.equalsIgnoreCase(extension.nullabilitySeverity ?: 'warn')) {\n                                            warnings << msg21; perServiceWarn.computeIfAbsent(fqcn) { [] } << msg21\n                                        }\n                                        countW021++\n                                    }\n                                }\n                            }\n                        }\n\n                        // Note: we intentionally avoid scanning raw class bytes for impl internal\n                        // names to prevent false positives (e.g., substring matches in class names).\n                        // Purity is enforced via explicit signature/generic parsing above.\n                    } catch (ClassNotFoundException cnf) {\n                        def msg = \"Declared service '${fqcn}' not found in API output; ensure it is compiled in 'api' source set\\n  Fix: Add interface to src/api/java and to btraceExtension.services.\"\n                        errors << msg; perService.computeIfAbsent(fqcn) { [] } << msg\n                    } catch (Throwable t) {\n                        def msg = \"Failed to analyze service '${fqcn}': ${t.message}\"\n                        errors << msg; perService.computeIfAbsent(fqcn) { [] } << msg\n                    }\n                }\n                // Only warn when there is no way to obtain permissions: both scanning disabled\n                // and no explicit requiredPermissions provided. If scanning is enabled (default),\n                // permissions will be generated later when building the API JAR.\n                if (!extension.scanPermissions && (!extension.requiredPermissions || extension.requiredPermissions.isEmpty())) {\n                    project.logger.warn(\"[BTRACE-EXT] No permissions source configured; enable scanPermissions or set requiredPermissions\")\n                }\n                // Write grouped report\n                def reportDir = new File(project.buildDir, 'reports/btrace')\n                reportDir.mkdirs()\n                def report = new File(reportDir, 'service-api-validation.txt')\n                report.withWriter('UTF-8') { w ->\n                    w.println(\"BTrace Service API Validation Report\")\n                    w.println(\"Project: ${project.path}\")\n                    w.println()\n                    perService.each { k, v ->\n                        w.println(\"Service: ${k}\")\n                        if (v.isEmpty()) {\n                            w.println(\"  OK\")\n                        } else {\n                            v.each { w.println(\"  - ${it}\") }\n                        }\n                        w.println()\n                    }\n                    if (!perServiceWarn.isEmpty()) {\n                        w.println(\"Warnings:\")\n                        perServiceWarn.each { k, v ->\n                            if (v.isEmpty()) return\n                            w.println(\"Service: ${k}\")\n                            v.each { w.println(\"  - ${it}\") }\n                            w.println()\n                        }\n                    }\n                    // Summary\n                    w.println(\"Summary:\")\n                    w.println(\"  Missing @Nullable on interface returns (shimability): ${count022}\")\n                    if (!'off'.equalsIgnoreCase(extension.nullabilitySeverity ?: 'warn')) {\n                        w.println(\"  Missing return nullability annotations: ${countW020}\")\n                        w.println(\"  Missing parameter nullability annotations: ${countW021}\")\n                    }\n                    w.println()\n                    w.println(\"Total errors: ${errors.size()}\")\n                }\n                project.logger.lifecycle(\"[BTRACE-EXT] validation report: ${project.relativePath(report)}\")\n                if (!errors.isEmpty()) {\n                    errors.each { project.logger.error(\"[BTRACE-EXT] ${it}\") }\n                    throw new GradleException(\"BTrace extension API validation failed with ${errors.size()} error(s)\")\n                }\n                if (!warnings.isEmpty()) {\n                    warnings.each { project.logger.warn(\"[BTRACE-EXT] ${it}\") }\n                }\n                project.logger.lifecycle(\"[BTRACE-EXT] validateServiceApis: OK for ${services.size()} service(s)\")\n            }\n        }\n\n        // Summary report task that never fails; emits grouped violations with fixes\n        def serviceApiValidationReport = project.tasks.register('serviceApiValidationReport') {\n            dependsOn project.tasks.named('compileApiJava')\n            doLast {\n                // Reuse the validation task to produce the report; do not fail build\n                try {\n                    project.tasks.named('validateServiceApis').get().actions.each { it.execute(project.tasks.named('validateServiceApis').get()) }\n                } catch (Throwable t) {\n                    // ignore failures; report was already written by validate task\n                }\n                def report = new File(project.buildDir, 'reports/btrace/service-api-validation.txt')\n                if (report.exists()) {\n                    project.logger.lifecycle(\"[BTRACE-EXT] validation report available at: ${project.relativePath(report)}\")\n                    project.logger.quiet(report.getText('UTF-8'))\n                } else {\n                    project.logger.lifecycle('[BTRACE-EXT] No report generated (no services or validation skipped)')\n                }\n            }\n        }\n\n        // Task: Build Implementation JAR (requires Shadow plugin applied by the consumer project)\n        def implJarProviderRef = new Object[1]\n        project.pluginManager.withPlugin('com.github.johnrengelman.shadow') {\n            def shadowJarProvider = project.tasks.named('shadowJar', Jar)\n            project.afterEvaluate {\n                shadowJarProvider.configure {\n                    from project.sourceSets.impl.output\n                    configurations = [project.configurations.implRuntimeClasspath]\n                    archiveClassifier = 'impl'\n                    archiveBaseName = project.name\n\n                    // Apply relocations from extension metadata\n                    extension.shadedPackages.each { from, to ->\n                        relocate from, to\n                    }\n\n                    // Minimize to remove unused classes\n                    minimize()\n                }\n            }\n            implJarProviderRef[0] = shadowJarProvider\n        }\n\n        // Wrapper task to build implementation jar via selected strategy\n        def buildImplJar = project.tasks.register('buildImplJar') {\n            doFirst {\n                if (implJarProviderRef[0] == null) {\n                    throw new IllegalStateException(\"Shadow plugin ('com.github.johnrengelman.shadow') must be applied in the project using the BTrace extension plugin.\")\n                }\n            }\n            dependsOn { implJarProviderRef[0] }\n        }\n\n        // Configure API JAR manifest with extension metadata\n        project.afterEvaluate {\n            if (implJarProviderRef[0] == null) {\n                def ext = project.extensions.findByType(BTraceExtensionMetadata)\n                boolean autoApplied = (ext == null) ? true : (ext.autoApplyShadow != false)\n                String hint = autoApplied ? \"Ensure the Shadow plugin is resolvable/available.\" : \"Enable auto-apply (btraceExtension.autoApplyShadow=true) or apply Shadow explicitly.\"\n                throw new GradleException(\"[BTRACE-EXT] Shadow plugin is required for ${project.path}. Apply id 'com.github.johnrengelman.shadow' (or alias(libs.plugins.shadow)). ${hint}\")\n            }\n            def implArchiveProvider = ((org.gradle.api.tasks.TaskProvider) implJarProviderRef[0]).flatMap { it.archiveFile }\n            buildApiJar.configure {\n                // Ensure we consider impl jar and classpath as inputs and we run when they change\n                dependsOn { implJarProviderRef[0] }\n                inputs.files(implArchiveProvider)\n                inputs.files(project.configurations.implRuntimeClasspath)\n                doFirst {\n                    // Compute permissions: scan impl jar and transitive classpath, then merge with overrides\n                    def implJar = implArchiveProvider.get().asFile\n                    Set<String> scannedPerms = [] as Set\n                    if (extension.scanPermissions) {\n                        Set<File> cp = [] as Set\n                        try {\n                            cp = project.configurations.implRuntimeClasspath.resolve() as Set<File>\n                        } catch (Throwable ignore) { }\n                        scannedPerms = PermissionScanner.scan(implJar, cp)\n                    }\n                    Set<String> mergedPerms = [] as Set\n                    mergedPerms.addAll(scannedPerms)\n                    mergedPerms.addAll(extension.requiredPermissions)\n\n                    // Emit concise info about permissions for traceability\n                    if (extension.scanPermissions) {\n                        project.logger.lifecycle(\"[BTRACE-EXT] permissions: scanned=${scannedPerms} merged=${mergedPerms}\")\n                    } else {\n                        project.logger.lifecycle(\"[BTRACE-EXT] permissions: merged=${mergedPerms} (scan disabled)\")\n                    }\n\n                    // Cross-check: ensure manifest permissions cover descriptor-declared requirements\n                    try {\n                        def cp = new LinkedHashSet<File>()\n                        cp.addAll(project.sourceSets.api.output.classesDirs.files)\n                        try { cp.addAll(project.sourceSets.api.compileClasspath.files) } catch (Throwable ignore) {}\n                        URLClassLoader cl = new URLClassLoader(cp.collect { it.toURI().toURL() } as URL[], (ClassLoader) null)\n                        def enumConstName = { Object enumConst ->\n                            if (enumConst instanceof List && enumConst.size() >= 2) {\n                                return String.valueOf(enumConst[1]).toUpperCase(Locale.ROOT)\n                            }\n                            return null\n                        }\n                        Set<String> annotatedPerms = [] as Set\n                        (extension.services as List<String>).each { String fqcn ->\n                            try {\n                                def res = fqcn.replace('.', '/') + '.class'\n                                def is = cl.getResourceAsStream(res)\n                                if (is == null) return\n                                def cr = new ClassReader(is)\n                                def cn = new ClassNode()\n                                cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                                (cn.visibleAnnotations ?: []).each { an ->\n                                    if (an.desc == 'Lorg/openjdk/btrace/core/extensions/ServiceDescriptor;') {\n                                        def vals = an.values ?: []\n                                        for (int i = 0; i < vals.size(); i += 2) {\n                                            if (vals[i] == 'permissions') {\n                                                def arr = vals[i+1] as List\n                                                arr?.each { ev ->\n                                                    def n = enumConstName(ev)\n                                                    if (n != null) annotatedPerms.add(n)\n                                                }\n                                            }\n                                        }\n                                    }\n                                }\n                                (cn.invisibleAnnotations ?: []).each { an ->\n                                    if (an.desc == 'Lorg/openjdk/btrace/core/extensions/ServiceDescriptor;') {\n                                        def vals = an.values ?: []\n                                        for (int i = 0; i < vals.size(); i += 2) {\n                                            if (vals[i] == 'permissions') {\n                                                def arr = vals[i+1] as List\n                                                arr?.each { ev ->\n                                                    def n = enumConstName(ev)\n                                                    if (n != null) annotatedPerms.add(n)\n                                                }\n                                            }\n                                        }\n                                    }\n                                }\n                            } catch (Throwable ignore) { }\n                        }\n                        // Also include package-level ExtensionDescriptor.permissions()\n                        project.sourceSets.api.output.classesDirs.files.each { File dir ->\n                            if (!dir.exists()) return\n                            dir.eachFileRecurse { f ->\n                                if (!f.name.equals('package-info.class')) return\n                                FileInputStream is2 = new FileInputStream(f)\n                                byte[] bytes2\n                                try { bytes2 = is2.bytes } finally { try { is2.close() } catch (Throwable ignore) {} }\n                                def cr2 = new ClassReader(bytes2)\n                                def cn2 = new ClassNode(); cr2.accept(cn2, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                                (cn2.visibleAnnotations ?: []).each { an ->\n                                    if (an.desc == 'Lorg/openjdk/btrace/core/extensions/ExtensionDescriptor;') {\n                                        def vals = an.values ?: []\n                                        for (int i = 0; i < vals.size(); i += 2) {\n                                            if (vals[i] == 'permissions') {\n                                                def arr = vals[i+1] as List\n                                                arr?.each { ev ->\n                                                    def n = enumConstName(ev)\n                                                    if (n != null) annotatedPerms.add(n)\n                                                }\n                                            }\n                                        }\n                                    }\n                                }\n                                (cn2.invisibleAnnotations ?: []).each { an ->\n                                    if (an.desc == 'Lorg/openjdk/btrace/core/extensions/ExtensionDescriptor;') {\n                                        def vals = an.values ?: []\n                                        for (int i = 0; i < vals.size(); i += 2) {\n                                            if (vals[i] == 'permissions') {\n                                                def arr = vals[i+1] as List\n                                                arr?.each { ev ->\n                                                    def n = enumConstName(ev)\n                                                    if (n != null) annotatedPerms.add(n)\n                                                }\n                                            }\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                        Set<String> manifestPerms = mergedPerms.collect { it.toString().toUpperCase(Locale.ROOT) } as Set\n                        Set<String> missing = annotatedPerms.findAll { !manifestPerms.contains(it) } as Set\n                        if (!missing.isEmpty()) {\n                            throw new GradleException(\"[BTRACE-EXT] Manifest permissions missing annotated requirements: ${missing}. Fix: enable scanPermissions or add to requiredPermissions.\")\n                        }\n                    } catch (GradleException ge) {\n                        throw ge\n                    } catch (Throwable t) {\n                        project.logger.warn(\"[BTRACE-EXT] permission alignment check failed to run: ${t.message}\")\n                    }\n\n                    def shadedPkgs = extension.shadedPackages.collect { k, v -> \"$k->$v\" }.join(',')\n                    def servicesStr = extension.services.join(',')\n                    def requiresStr = extension.requiresExtensions.join(',')\n                    def permsStr = mergedPerms.join(',')\n\n                    manifest {\n                        attributes(\n                            'BTrace-Extension-Id': extension.id,\n                            'BTrace-Extension-Version': extension.version,\n                            'BTrace-Extension-Name': extension.name,\n                            'BTrace-Extension-Description': extension.description,\n                            'BTrace-API-Version': '2.3+',\n                            'BTrace-Java-Version': '8+',\n                            'BTrace-Extension-Services': {\n                                if (servicesStr && !servicesStr.isEmpty()) return servicesStr\n                                // If not explicitly configured, detect services via @ServiceDescriptor in API output\n                                def detected = new LinkedHashSet<String>()\n                                project.sourceSets.api.output.classesDirs.files.each { File dir ->\n                                    if (!dir.exists()) return\n                                    dir.eachFileRecurse { f ->\n                                        if (!f.name.endsWith('.class')) return\n                                        def rel = dir.toPath().relativize(f.toPath()).toString()\n                                        def fq = rel.replace(File.separatorChar, (char)'.').replaceAll(/\\.class$/, '')\n                                        FileInputStream is = new FileInputStream(f)\n                                        byte[] bytes\n                                        try { bytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                                        def cr = new ClassReader(bytes)\n                                        def cn = new ClassNode(); cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                                        boolean isInterface = (cn.access & Opcodes.ACC_INTERFACE) != 0\n                                        boolean hasMarker = false\n                                        (cn.visibleAnnotations ?: []).each { hasMarker |= (it.desc == 'Lorg/openjdk/btrace/core/extensions/ServiceDescriptor;') }\n                                        (cn.invisibleAnnotations ?: []).each { hasMarker |= (it.desc == 'Lorg/openjdk/btrace/core/extensions/ServiceDescriptor;') }\n                                        if (hasMarker && isInterface) detected.add(fq)\n                                    }\n                                }\n                                return detected.join(',')\n                            }.call(),\n                            'BTrace-Extension-Requires': requiresStr,\n                            'BTrace-Shaded-Packages': shadedPkgs,\n                            'BTrace-Extension-Impl': \"${project.name}-${extension.version}-impl.jar\",\n                            'BTrace-Extension-Permissions': permsStr,\n                            // Read exports index (if present) and add a short summary attribute\n                            'BTrace-Extension-Exports': {\n                                try {\n                                    def idxFile = new File(project.buildDir, 'generated/resources/btraceExports/META-INF/btrace/exports.index')\n                                    List<String> lines = []\n                                    if (idxFile.exists()) {\n                                        lines = idxFile.readLines('UTF-8')\n                                    } else {\n                                        lines = extension.services as List<String>\n                                    }\n                                    int limit = 20\n                                    def head = lines.take(limit)\n                                    def extra = Math.max(0, lines.size() - limit)\n                                    return head.join(',') + (extra > 0 ? \", +${extra} more\" : '')\n                                } catch (Throwable ignore) {\n                                    return servicesStr\n                                }\n                            }.call()\n                        )\n                    }\n                }\n            }\n        }\n\n        // Generate shims Java sources for API interfaces\n        def shimsSrcDir = new File(project.buildDir, 'generated/sources/btraceShims/api')\n        def shimsClsDir = new File(project.buildDir, 'generated/classes/btraceShims/api')\n        def shimsResDir = new File(project.buildDir, 'generated/resources/btraceShims')\n\n        def generateServiceShims = project.tasks.register('generateServiceShims') {\n            dependsOn project.tasks.named('compileApiJava')\n            doLast {\n                shimsSrcDir.mkdirs()\n                // Build ClassLoader over API outputs to reflect methods\n                def cp = new LinkedHashSet<File>()\n                cp.addAll(project.sourceSets.api.output.classesDirs.files)\n                try { cp.addAll(project.sourceSets.api.compileClasspath.files) } catch (Throwable ignore) {}\n                URLClassLoader cl = new URLClassLoader(cp.collect { it.toURI().toURL() } as URL[], (ClassLoader) null)\n                // Discover ALL API interfaces in the api output\n                def apiInterfaces = new LinkedHashSet<String>()\n                project.sourceSets.api.output.classesDirs.files.each { File dir ->\n                    if (!dir.exists()) return\n                    dir.eachFileRecurse { f ->\n                        if (f.name.endsWith('.class')) {\n                            def rel = dir.toPath().relativize(f.toPath()).toString()\n                            def fq = rel.replace(File.separatorChar, (char)'.').replaceAll(/\\.class$/, '')\n                            // Use ASM to filter interfaces (skip annotations)\n                            def is = new FileInputStream(f)\n                            byte[] bytes\n                            try { bytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                            def cr = new ClassReader(bytes)\n                            int acc = cr.access\n                            boolean isInterface = (acc & Opcodes.ACC_INTERFACE) != 0\n                            boolean isAnnotation = (acc & Opcodes.ACC_ANNOTATION) != 0\n                            if (isInterface && !isAnnotation) {\n                                apiInterfaces.add(fq)\n                            }\n                        }\n                    }\n                }\n                if (apiInterfaces.isEmpty()) {\n                    project.logger.warn('[BTRACE-EXT] No API interfaces found; skipping shim generation')\n                    return\n                }\n                // Optionally restrict to interfaces reachable from services via descriptors + generics\n                def targetInterfaces = new LinkedHashSet<String>()\n                if (extension.generateShimsReachableOnly) {\n                    def services = (extension.services as List<String>) ?: []\n                    // BFS closure over referenced API interface types\n                    def visited = new HashSet<String>()\n                    def queue = new ArrayDeque<String>(services)\n                    while (!queue.isEmpty()) {\n                        def cur = queue.removeFirst()\n                        if (cur == null || visited.contains(cur)) continue\n                        visited.add(cur)\n                        if (apiInterfaces.contains(cur)) targetInterfaces.add(cur)\n                        try {\n                            def res = cur.replace('.', '/') + '.class'\n                            def is = cl.getResourceAsStream(res)\n                            if (is == null) continue\n                            byte[] bytes; try { bytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                            def cr = new ClassReader(bytes)\n                            def cn = new ClassNode(); cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                            def addType = { String fq -> if (fq!=null && apiInterfaces.contains(fq) && !visited.contains(fq)) queue.addLast(fq) }\n                            // class generics\n                            if (cn.signature != null) {\n                                try {\n                                    new SignatureReader(cn.signature).accept(new SignatureVisitor(Opcodes.ASM9){\n                                        void visitClassType(String name){ addType(name?.replace('/', '.')) }\n                                        void visitInnerClassType(String name){ addType(name?.replace('/', '.')) }\n                                        SignatureVisitor visitSuperclass(){ return this }\n                                        SignatureVisitor visitInterface(){ return this }\n                                        SignatureVisitor visitTypeArgument(char w){ return this }\n                                        SignatureVisitor visitClassBound(){ return this }\n                                        SignatureVisitor visitInterfaceBound(){ return this }\n                                    })\n                                } catch(Throwable ignore){}\n                            }\n                            // method descriptors + generics\n                            cn.methods?.each { MethodNode mn ->\n                                def mt = Type.getMethodType(mn.desc)\n                                [mt.returnType].each { t -> if (t.sort==Type.OBJECT) addType(t.className) }\n                                mt.argumentTypes?.each { t -> if (t.sort==Type.OBJECT) addType(t.className) }\n                                if (mn.signature != null) {\n                                    try {\n                                        new SignatureReader(mn.signature).accept(new SignatureVisitor(Opcodes.ASM9){\n                                            void visitClassType(String name){ addType(name?.replace('/', '.')) }\n                                            void visitInnerClassType(String name){ addType(name?.replace('/', '.')) }\n                                            SignatureVisitor visitParameterType(){ return this }\n                                            SignatureVisitor visitReturnType(){ return this }\n                                            SignatureVisitor visitExceptionType(){ return this }\n                                            SignatureVisitor visitArrayType(){ return this }\n                                            SignatureVisitor visitTypeArgument(char w){ return this }\n                                        })\n                                    } catch(Throwable ignore){}\n                                }\n                            }\n                        } catch (Throwable ignore) {}\n                    }\n                } else {\n                    targetInterfaces.addAll(apiInterfaces)\n                }\n\n                // Generate shims for selected API interfaces\n                targetInterfaces.each { String fqcn ->\n                    try {\n                        Class<?> c = Class.forName(fqcn, false, cl)\n                        if (!c.isInterface()) return\n                        def pkg = c.package?.name ?: ''\n                        def simple = c.simpleName\n                        def shimPkg = (pkg ? pkg + '.btrace.shim' : 'btrace.shim')\n                        def dir = new File(shimsSrcDir, shimPkg.replace('.', '/'))\n                        dir.mkdirs()\n                        def noopName = \"NoOp${simple}\"\n                        def throwName = \"Throwing${simple}\"\n                        def methods = c.getMethods().findAll { it.declaringClass == c }\n                        // Emit NoOp\n                        new File(dir, noopName + '.java').withWriter('UTF-8') { w ->\n                            w.println(\"package ${shimPkg};\")\n                            w.println()\n                            w.println(\"public final class ${noopName} implements ${fqcn} {\")\n                            w.println(\"  public static final ${fqcn} INSTANCE = new ${noopName}();\")\n                            methods.each { m ->\n                                def ret = m.returnType\n                                def params = []\n                                m.parameterTypes.eachWithIndex { pt, idx -> params << (pt.name + \" p\" + idx) }\n                                w.println(\"  public ${ret.name} ${m.name}(${params.join(', ')}) {\")\n                                if (ret == Void.TYPE) {\n                                    w.println(\"    return;\")\n                                } else if (ret.isPrimitive()) {\n                                    if (ret == Boolean.TYPE) w.println(\"    return false;\")\n                                    else if (ret == Character.TYPE) w.println(\"    return (char)0;\")\n                                    else if (ret == Byte.TYPE) w.println(\"    return (byte)0;\")\n                                    else if (ret == Short.TYPE) w.println(\"    return (short)0;\")\n                                    else if (ret == Integer.TYPE) w.println(\"    return 0;\")\n                                    else if (ret == Long.TYPE) w.println(\"    return 0L;\")\n                                    else if (ret == Float.TYPE) w.println(\"    return 0f;\")\n                                    else if (ret == Double.TYPE) w.println(\"    return 0d;\")\n                                } else if (ret.isArray() && ret.componentType.isInterface() && apiInterfaces.contains(ret.componentType.name)) {\n                                    // Return empty array of API interface type\n                                    w.println(\"    return new ${ret.componentType.name}[0];\")\n                                } else if (ret.isInterface() && apiInterfaces.contains(ret.name)) {\n                                    // Return nested shim INSTANCE (or this if fluent self-return)\n                                    if (ret.name == fqcn) {\n                                        w.println(\"    return this;\")\n                                    } else {\n                                        def retSimple = ret.simpleName\n                                        def retShimFqcn = (ret.package?.name ? ret.package.name + '.btrace.shim.NoOp' + retSimple : 'btrace.shim.NoOp' + retSimple)\n                                        w.println(\"    return ${retShimFqcn}.INSTANCE;\")\n                                    }\n                                } else if (m.genericReturnType instanceof java.lang.reflect.ParameterizedType) {\n                                    def pt = (java.lang.reflect.ParameterizedType) m.genericReturnType\n                                    def raw = (pt.rawType instanceof Class) ? (Class) pt.rawType : null\n                                    if (raw != null) {\n                                        def rawName = raw.name\n                                        if (rawName == 'java.util.List' || rawName == 'java.util.Collection' || rawName == 'java.lang.Iterable') {\n                                            w.println(\"    return java.util.Collections.emptyList();\")\n                                        } else if (rawName == 'java.util.Set') {\n                                            w.println(\"    return java.util.Collections.emptySet();\")\n                                        } else if (rawName == 'java.util.Queue' || rawName == 'java.util.Deque') {\n                                            w.println(\"    return new java.util.ArrayDeque<>();\")\n                                        } else if (rawName == 'java.util.Map') {\n                                            w.println(\"    return java.util.Collections.emptyMap();\")\n                                        } else if (rawName == 'java.util.Optional') {\n                                            w.println(\"    return java.util.Optional.empty();\")\n                                        } else if (rawName == 'java.util.stream.Stream') {\n                                            w.println(\"    return java.util.stream.Stream.empty();\")\n                                        } else if (rawName == 'java.util.stream.IntStream') {\n                                            w.println(\"    return java.util.stream.IntStream.empty();\")\n                                        } else if (rawName == 'java.util.stream.LongStream') {\n                                            w.println(\"    return java.util.stream.LongStream.empty();\")\n                                        } else if (rawName == 'java.util.stream.DoubleStream') {\n                                            w.println(\"    return java.util.stream.DoubleStream.empty();\")\n                                        } else {\n                                            w.println(\"    return null;\")\n                                        }\n                                    }\n                                } else {\n                                    w.println(\"    return null;\")\n                                }\n                                w.println(\"  }\")\n                            }\n                            // equals/hashCode/toString\n                            w.println(\"  public boolean equals(Object o) { return this == o; }\")\n                            w.println(\"  public int hashCode() { return System.identityHashCode(this); }\")\n                            w.println(\"  public String toString() { return \\\"NoOp${simple}\\\"; }\")\n                            w.println(\"}\")\n                        }\n                        // Emit Throwing\n                        new File(dir, throwName + '.java').withWriter('UTF-8') { w ->\n                            w.println(\"package ${shimPkg};\")\n                            w.println()\n                            w.println(\"public final class ${throwName} implements ${fqcn} {\")\n                            w.println(\"  public static final ${fqcn} INSTANCE = new ${throwName}();\")\n                            w.println(\"  private static RuntimeException unavailable() { return new IllegalStateException(\\\"BTrace optional service unavailable: ${fqcn}\\\"); }\")\n                            methods.each { m ->\n                                def ret = m.returnType\n                                def params = []\n                                m.parameterTypes.eachWithIndex { pt, idx -> params << (pt.name + \" p\" + idx) }\n                                w.println(\"  public ${ret.name} ${m.name}(${params.join(', ')}) {\")\n                                w.println(\"    throw unavailable();\")\n                                w.println(\"  }\")\n                            }\n                            // equals/hashCode/toString\n                            w.println(\"  public boolean equals(Object o) { return this == o; }\")\n                            w.println(\"  public int hashCode() { return System.identityHashCode(this); }\")\n                            w.println(\"  public String toString() { return \\\"Throwing${simple}\\\"; }\")\n                            w.println(\"}\")\n                        }\n                    } catch (Throwable t) {\n                        project.logger.warn(\"[BTRACE-EXT] Skipping shim generation for ${fqcn}: ${t.message}\")\n                    }\n                }\n            }\n        }\n\n        def compileServiceShims = project.tasks.register('compileServiceShims', JavaCompile) { t ->\n            dependsOn generateServiceShims\n            source = project.fileTree(shimsSrcDir)\n            destinationDirectory.set(shimsClsDir)\n            classpath = project.files(project.sourceSets.api.output.classesDirs, project.sourceSets.api.compileClasspath)\n            options.release = 8\n        }\n\n        def generateShimIndex = project.tasks.register('generateShimIndex') {\n            dependsOn generateServiceShims\n            doLast {\n                // Recompute the same target set as generateServiceShims (respect generateShimsReachableOnly)\n                def apiInterfaces = new LinkedHashSet<String>()\n                project.sourceSets.api.output.classesDirs.files.each { File dir ->\n                    if (!dir.exists()) return\n                    dir.eachFileRecurse { f ->\n                        if (f.name.endsWith('.class')) {\n                            def rel = dir.toPath().relativize(f.toPath()).toString()\n                            def fq = rel.replace(File.separatorChar, (char)'.').replaceAll(/\\.class$/, '')\n                            def is = new FileInputStream(f)\n                            byte[] bytes\n                            try { bytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                            def cr = new ClassReader(bytes)\n                            int acc = cr.access\n                            boolean isInterface = (acc & Opcodes.ACC_INTERFACE) != 0\n                            boolean isAnnotation = (acc & Opcodes.ACC_ANNOTATION) != 0\n                            if (isInterface && !isAnnotation) apiInterfaces.add(fq)\n                        }\n                    }\n                }\n                if (apiInterfaces.isEmpty()) return\n                def cp = new LinkedHashSet<File>()\n                cp.addAll(project.sourceSets.api.output.classesDirs.files)\n                try { cp.addAll(project.sourceSets.api.compileClasspath.files) } catch (Throwable ignore) {}\n                URLClassLoader cl = new URLClassLoader(cp.collect { it.toURI().toURL() } as URL[], (ClassLoader) null)\n                def targetInterfaces = new LinkedHashSet<String>()\n                if (extension.generateShimsReachableOnly) {\n                    def services = (extension.services as List<String>) ?: []\n                    if (services.isEmpty()) {\n                        // fall back to detected annotated services\n                        project.sourceSets.api.output.classesDirs.files.each { File dir ->\n                            if (!dir.exists()) return\n                            dir.eachFileRecurse { f ->\n                                if (!f.name.endsWith('.class')) return\n                                def rel = dir.toPath().relativize(f.toPath()).toString()\n                                def fq = rel.replace(File.separatorChar, (char)'.').replaceAll(/\\.class$/, '')\n                                FileInputStream is = new FileInputStream(f)\n                                byte[] bytes\n                                try { bytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                                def cr = new ClassReader(bytes)\n                                def cn = new ClassNode(); cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                                boolean isInterface = (cn.access & Opcodes.ACC_INTERFACE) != 0\n                                boolean hasMarker = false\n                                (cn.visibleAnnotations ?: []).each { hasMarker |= (it.desc == 'Lorg/openjdk/btrace/core/extensions/ServiceDescriptor;') }\n                                (cn.invisibleAnnotations ?: []).each { hasMarker |= (it.desc == 'Lorg/openjdk/btrace/core/extensions/ServiceDescriptor;') }\n                                if (hasMarker && isInterface) services.add(fq)\n                            }\n                        }\n                    }\n                    def visited = new HashSet<String>()\n                    def queue = new ArrayDeque<String>(services)\n                    while (!queue.isEmpty()) {\n                        def cur = queue.removeFirst()\n                        if (cur == null || visited.contains(cur)) continue\n                        visited.add(cur)\n                        if (apiInterfaces.contains(cur)) targetInterfaces.add(cur)\n                        try {\n                            def res = cur.replace('.', '/') + '.class'\n                            def is = cl.getResourceAsStream(res)\n                            if (is == null) continue\n                            byte[] bytes; try { bytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                            def cr = new ClassReader(bytes)\n                            def cn = new ClassNode(); cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                            def addType = { String fq -> if (fq!=null && apiInterfaces.contains(fq) && !visited.contains(fq)) queue.addLast(fq) }\n                            if (cn.signature != null) {\n                                try { new SignatureReader(cn.signature).accept(new SignatureVisitor(Opcodes.ASM9){\n                                    void visitClassType(String name){ addType(name?.replace('/', '.')) }\n                                    void visitInnerClassType(String name){ addType(name?.replace('/', '.')) }\n                                    SignatureVisitor visitSuperclass(){ return this }\n                                    SignatureVisitor visitInterface(){ return this }\n                                    SignatureVisitor visitTypeArgument(char w){ return this }\n                                    SignatureVisitor visitClassBound(){ return this }\n                                    SignatureVisitor visitInterfaceBound(){ return this }\n                                }) } catch(Throwable ignore){}\n                            }\n                            cn.methods?.each { MethodNode mn ->\n                                def mt = Type.getMethodType(mn.desc)\n                                [mt.returnType].each { t -> if (t.sort==Type.OBJECT) addType(t.className) }\n                                mt.argumentTypes?.each { t -> if (t.sort==Type.OBJECT) addType(t.className) }\n                                if (mn.signature != null) {\n                                    try { new SignatureReader(mn.signature).accept(new SignatureVisitor(Opcodes.ASM9){\n                                        void visitClassType(String name){ addType(name?.replace('/', '.')) }\n                                        void visitInnerClassType(String name){ addType(name?.replace('/', '.')) }\n                                        SignatureVisitor visitParameterType(){ return this }\n                                        SignatureVisitor visitReturnType(){ return this }\n                                        SignatureVisitor visitExceptionType(){ return this }\n                                        SignatureVisitor visitArrayType(){ return this }\n                                        SignatureVisitor visitTypeArgument(char w){ return this }\n                                    }) } catch(Throwable ignore){}\n                                }\n                            }\n                        } catch (Throwable ignore) {}\n                    }\n                } else {\n                    targetInterfaces.addAll(apiInterfaces)\n                }\n                def idxFile = new File(shimsResDir, 'META-INF/btrace/shims.index')\n                idxFile.parentFile.mkdirs()\n                idxFile.withWriter('UTF-8') { w ->\n                    targetInterfaces.each { String fqcn ->\n                        def pkg = fqcn.contains('.') ? fqcn.substring(0, fqcn.lastIndexOf('.')) : ''\n                        def simple = fqcn.substring(fqcn.lastIndexOf('.')+1)\n                        def shimPkg = (pkg ? pkg + '.btrace.shim' : 'btrace.shim')\n                        def noop = shimPkg + '.NoOp' + simple\n                        def thrw = shimPkg + '.Throwing' + simple\n                        w.println(\"${fqcn} = ${noop}, ${thrw}\")\n                    }\n                }\n            }\n        }\n\n        // Exports index: collect all API types referenced in service method signatures (return and params)\n        def exportsResDir = new File(project.buildDir, 'generated/resources/btraceExports')\n        def generateExportsIndex = project.tasks.register('generateExportsIndex') {\n            dependsOn project.tasks.named('compileApiJava')\n            doLast {\n                def services = extension.services as List<String>\n                if (!services || services.isEmpty()) {\n                    def detected = new LinkedHashSet<String>()\n                    project.sourceSets.api.output.classesDirs.files.each { File dir ->\n                        if (!dir.exists()) return\n                        dir.eachFileRecurse { f ->\n                            if (!f.name.endsWith('.class')) return\n                            def rel = dir.toPath().relativize(f.toPath()).toString()\n                            def fq = rel.replace(File.separatorChar, (char)'.').replaceAll(/\\.class$/, '')\n                            FileInputStream is = new FileInputStream(f)\n                            byte[] bytes\n                            try { bytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                            def cr = new ClassReader(bytes)\n                            def cn = new ClassNode(); cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                            boolean isInterface = (cn.access & Opcodes.ACC_INTERFACE) != 0\n                            boolean hasMarker = false\n                            (cn.visibleAnnotations ?: []).each { hasMarker |= (it.desc == 'Lorg/openjdk/btrace/core/extensions/ServiceDescriptor;') }\n                            (cn.invisibleAnnotations ?: []).each { hasMarker |= (it.desc == 'Lorg/openjdk/btrace/core/extensions/ServiceDescriptor;') }\n                            if (hasMarker && isInterface) detected.add(fq)\n                        }\n                    }\n                    services = detected as List<String>\n                }\n                if (!services || services.isEmpty()) return\n                def cp = new LinkedHashSet<File>()\n                cp.addAll(project.sourceSets.api.output.classesDirs.files)\n                try { cp.addAll(project.sourceSets.api.compileClasspath.files) } catch (Throwable ignore) {}\n                URLClassLoader cl = new URLClassLoader(cp.collect { it.toURI().toURL() } as URL[], (ClassLoader) null)\n\n                // Collect known API/impl class names to validate placement\n                def apiClassNames = new HashSet<String>()\n                project.sourceSets.api.output.classesDirs.files.each { File dir ->\n                    if (!dir.exists()) return\n                    dir.eachFileRecurse { f ->\n                        if (f.name.endsWith('.class')) {\n                            def rel = dir.toPath().relativize(f.toPath()).toString()\n                            apiClassNames.add(rel.replace(File.separatorChar, (char)'.').replaceAll(/\\.class$/, ''))\n                        }\n                    }\n                }\n                def implClassNames = new HashSet<String>()\n                project.sourceSets.impl.output.classesDirs.files.each { File dir ->\n                    if (!dir.exists()) return\n                    dir.eachFileRecurse { f ->\n                        if (f.name.endsWith('.class')) {\n                            def rel = dir.toPath().relativize(f.toPath()).toString()\n                            implClassNames.add(rel.replace(File.separatorChar, (char)'.').replaceAll(/\\.class$/, ''))\n                        }\n                    }\n                }\n\n                def exports = new LinkedHashSet<String>()\n                services.each { String fqcn ->\n                    try {\n                        exports.add(fqcn)\n                        def res = fqcn.replace('.', '/') + '.class'\n                        def is = cl.getResourceAsStream(res)\n                        if (is == null) return\n                        byte[] bytes\n                        try { bytes = is.bytes } finally { try { is.close() } catch (Throwable ignore) {} }\n                        def cr = new ClassReader(bytes)\n                        def cn = new ClassNode()\n                        cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG)\n                        // Class-level generic signature: capture bounds/supertypes/interface types\n                        if (cn.signature != null) {\n                            try {\n                                def collector = new SignatureVisitor(Opcodes.ASM9) {\n                                    @Override\n                                    void visitClassType(String name) { addType(name?.replace('/', '.')) }\n                                    @Override\n                                    void visitInnerClassType(String name) { addType(name?.replace('/', '.')) }\n                                    @Override\n                                    SignatureVisitor visitSuperclass() { return this }\n                                    @Override\n                                    SignatureVisitor visitInterface() { return this }\n                                    @Override\n                                    SignatureVisitor visitTypeArgument(char wildcard) { return this }\n                                    @Override\n                                    SignatureVisitor visitClassBound() { return this }\n                                    @Override\n                                    SignatureVisitor visitInterfaceBound() { return this }\n                                }\n                                new SignatureReader(cn.signature).accept(collector)\n                            } catch (Throwable ignored) { }\n                        }\n                        // Helper to add a referenced type found in signatures\n                        def addType = { String fq ->\n                            if (fq == null) return\n                            if (fq.startsWith('java.') || fq.startsWith('javax.') || fq.startsWith('jakarta.')) return\n                            if (apiClassNames.contains(fq)) {\n                                exports.add(fq)\n                            } else if (implClassNames.contains(fq)) {\n                                throw new GradleException(\"[BTRACE-EXT] API method references implementation type '${fq}'. Fix: move type to API module so probes can use it.\")\n                            }\n                        }\n\n                        cn.methods?.each { MethodNode mn ->\n                            def mt = Type.getMethodType(mn.desc)\n                            def all = [] as List<Type>\n                            all << mt.returnType\n                            all.addAll(mt.argumentTypes.toList())\n                            all.each { Type t ->\n                                def fq = null\n                                if (t.getSort() == Type.OBJECT) {\n                                    fq = t.getClassName()\n                                } else if (t.getSort() == Type.ARRAY && t.getElementType().getSort() == Type.OBJECT) {\n                                    fq = t.getElementType().getClassName()\n                                }\n                                addType(fq)\n                            }\n                            // Parse generic signature to capture type arguments\n                            if (mn.signature != null) {\n                                try {\n                                    def collector = new SignatureVisitor(Opcodes.ASM9) {\n                                        @Override\n                                        SignatureVisitor visitParameterType() { return this }\n                                        @Override\n                                        SignatureVisitor visitReturnType() { return this }\n                                        @Override\n                                        SignatureVisitor visitExceptionType() { return this }\n                                        @Override\n                                        SignatureVisitor visitArrayType() { return this }\n                                        @Override\n                                        void visitClassType(String name) { addType(name?.replace('/', '.')) }\n                                        @Override\n                                        void visitInnerClassType(String name) { addType(name?.replace('/', '.')) }\n                                        @Override\n                                        void visitTypeVariable(String name) { }\n                                        @Override\n                                        void visitBaseType(char descriptor) { }\n                                        @Override\n                                        SignatureVisitor visitTypeArgument(char wildcard) { return this }\n                                    }\n                                    new SignatureReader(mn.signature).accept(collector)\n                                } catch (Throwable ignored) { }\n                            }\n                        }\n                    } catch (GradleException ge) {\n                        throw ge\n                    } catch (Throwable t) {\n                        project.logger.warn(\"[BTRACE-EXT] export scan skipped for ${fqcn}: ${t.message}\")\n                    }\n                }\n\n                if (!exports.isEmpty()) {\n                    def idxFile = new File(exportsResDir, 'META-INF/btrace/exports.index')\n                    idxFile.parentFile.mkdirs()\n                    idxFile.withWriter('UTF-8') { w ->\n                        exports.each { w.println(it) }\n                    }\n                    project.logger.lifecycle(\"[BTRACE-EXT] exports: ${exports.size()} types\")\n                }\n            }\n        }\n        def packageExtension = project.tasks.register('packageExtension', Zip) {\n            dependsOn buildApiJar, buildImplJar, compileServiceShims, generateShimIndex, generateExportsIndex, validateServiceApis\n            archiveBaseName = project.name\n            archiveClassifier = 'extension'\n\n            from(buildApiJar.map { it.archiveFile })\n            from(((org.gradle.api.tasks.TaskProvider) implJarProviderRef[0]).flatMap { it.archiveFile })\n        }\n\n        // Disable default jar task (use packageExtension instead)\n        project.tasks.named('jar') {\n            enabled = false\n        }\n\n        // Configure artifacts for consumption\n        project.configurations {\n            apiElements.outgoing.artifacts.clear()\n            apiElements.outgoing.artifact(buildApiJar)\n\n            runtimeElements.outgoing.artifacts.clear()\n            runtimeElements.outgoing.artifact(buildApiJar)\n            runtimeElements.outgoing.artifact(packageExtension)\n        }\n\n        // Make extension ZIP the default archive artifact\n        project.artifacts { archives packageExtension }\n\n        // Include shims classes and index in API JAR\n        buildApiJar.configure {\n            dependsOn compileServiceShims, generateShimIndex, generateExportsIndex\n            from(shimsClsDir)\n            from(shimsResDir)\n            from(exportsResDir)\n        }\n\n        // Aux tasks: API sources and javadoc jars\n        def apiSourcesJar = project.tasks.register('apiSourcesJar', Jar) {\n            archiveBaseName = project.name\n            archiveClassifier = 'api-sources'\n            duplicatesStrategy = DuplicatesStrategy.EXCLUDE\n            from project.sourceSets.api.allSource\n        }\n        def apiJavadoc = project.tasks.register('apiJavadoc', Javadoc) {\n            source = project.sourceSets.api.allJava\n            classpath = project.files(project.sourceSets.api.output.classesDirs, project.sourceSets.api.compileClasspath)\n            destinationDir = new File(project.buildDir, 'docs/api')\n            options.encoding = 'UTF-8'\n        }\n        def apiJavadocJar = project.tasks.register('apiJavadocJar', Jar) {\n            dependsOn apiJavadoc\n            archiveBaseName = project.name\n            archiveClassifier = 'api-javadoc'\n            from apiJavadoc.map { it.destinationDir }\n        }\n\n        // Configure publishing if maven-publish is present\n        if (project.plugins.hasPlugin('maven-publish')) {\n            project.publishing {\n                publications {\n                    mavenExtension(org.gradle.api.publish.maven.MavenPublication) {\n                        groupId = project.group as String\n                        artifactId = project.name\n                        version = project.version as String\n\n                        artifact(buildApiJar) { classifier = 'api' }\n                        artifact(apiSourcesJar)\n                        artifact(apiJavadocJar)\n                        artifact(packageExtension) { classifier = 'extension' }\n\n                        pom {\n                            name = project.provider { extension.name }\n                            description = project.provider { extension.description }\n                        }\n                    }\n                }\n            }\n        }\n\n        // Tests can see both api and impl outputs\n        project.afterEvaluate {\n            project.dependencies {\n                testImplementation project.sourceSets.api.output\n                testImplementation project.sourceSets.impl.output\n            }\n            // Fail build on validation errors via check lifecycle\n            project.tasks.matching { it.name == 'check' }.configureEach { it.dependsOn validateServiceApis }\n        }\n    }\n}\n\nclass BTraceExtensionMetadata {\n    String id\n    String version\n    String name\n    String description\n    List<String> services = []\n    List<String> requiresExtensions = []\n    Map<String, String> shadedPackages = [:]\n    // Whether to auto-apply the Shadow plugin. Default: true\n    boolean autoApplyShadow = true\n    boolean scanPermissions = true\n    List<String> requiredPermissions = []\n    // Configurable nullability annotations (FQCN). Defaults cover javax/jspecify/jetbrains/jakarta\n    List<String> nullableAnnotations = []\n    List<String> nonnullAnnotations = []\n    // Validation severity knobs\n    // nullabilitySeverity: 'off' | 'warn' | 'error' (default: 'warn')\n    String nullabilitySeverity = 'warn'\n    // shimabilitySeverity: 'warn' | 'error' (default: 'error')\n    String shimabilitySeverity = 'error'\n    // apiCtorSeverity: 'off' | 'warn' | 'error' (default: 'error')\n    String apiCtorSeverity = 'error'\n    // Generate shims only for interfaces reachable from declared services (via signatures + generics)\n    // Set to false to generate shims for all API interfaces.\n    boolean generateShimsReachableOnly = true\n}\n"
  },
  {
    "path": "btrace-gradle-plugin/src/main/groovy/org/openjdk/btrace/gradle/PermissionScanner.groovy",
    "content": "package org.openjdk.btrace.gradle\n\nimport java.io.File\nimport java.io.FileInputStream\nimport java.io.IOException\nimport java.io.InputStream\nimport java.util.ArrayDeque\nimport java.util.Collection\nimport java.util.Collections\nimport java.util.Deque\nimport java.util.List\nimport java.util.Set\nimport java.util.zip.ZipEntry\nimport java.util.zip.ZipFile\nimport java.util.zip.ZipInputStream\nimport org.objectweb.asm.ClassReader\nimport org.objectweb.asm.tree.ClassNode\nimport org.objectweb.asm.tree.AbstractInsnNode\nimport org.objectweb.asm.tree.MethodInsnNode\nimport org.objectweb.asm.tree.FieldInsnNode\nimport org.objectweb.asm.tree.InvokeDynamicInsnNode\nimport org.objectweb.asm.Opcodes\nimport org.objectweb.asm.tree.LdcInsnNode\n\n/**\n * Scans a compiled extension implementation JAR to infer required permissions\n * based on referenced JDK/runtime APIs.\n */\nfinal class PermissionScanner {\n\n    static Set<String> scan(File jarFile, Collection<File> classpath = Collections.emptyList()) {\n        Set<String> perms = [] as Set\n        if (jarFile == null || !jarFile.exists()) return perms\n\n        List<File> sources = []\n        sources.add(jarFile)\n        classpath?.each { File f ->\n            if (f == null || !f.exists()) return\n            def path = f.absolutePath\n            if (path.contains('/btrace-core') || path.contains('/btrace-runtime') || path.contains('/btrace-instr') || path.contains('/btrace-agent')) return\n            sources.add(f)\n        }\n\n        Set<String> visited = [] as Set\n        Deque<String> queue = new ArrayDeque<>()\n        new ZipFile(jarFile).withCloseable { zip ->\n            zip.entries().each { e ->\n                if (!e.isDirectory() && e.name.endsWith('.class')) {\n                    queue.add(e.name.substring(0, e.name.length() - '.class'.length()))\n                }\n            }\n        }\n\n        while (!queue.isEmpty()) {\n            String cn = queue.removeFirst()\n            if (!visited.add(cn)) continue\n            InputStream is = openClassStream(cn, sources)\n            if (is == null) continue\n            try {\n                ClassReader cr = new ClassReader(is)\n                ClassNode node = new ClassNode()\n                cr.accept(node, 0)\n                node.methods.each { m ->\n                    for (AbstractInsnNode insn = m.instructions.first; insn != null; insn = insn.next) {\n                        if (insn instanceof MethodInsnNode) {\n                            MethodInsnNode min = (MethodInsnNode) insn\n                            handleMethod(min, perms, m, insn)\n                            String owner = min.owner\n                            if (owner != null && !owner.startsWith('java/') && !owner.startsWith('javax/')) {\n                                queue.add(owner)\n                            }\n                        } else if (insn instanceof FieldInsnNode) {\n                            handleField(((FieldInsnNode) insn), perms)\n                        }\n                    }\n                }\n            } finally {\n                is.close()\n            }\n        }\n        return perms\n    }\n\n    private static void scanClass(InputStream in, Set<String> perms) {\n        ClassReader cr = new ClassReader(in)\n        ClassNode cn = new ClassNode()\n        cr.accept(cn, 0)\n\n        cn.methods.each { m ->\n            for (AbstractInsnNode insn = m.instructions.first; insn != null; insn = insn.next) {\n                if (insn instanceof MethodInsnNode) {\n                    handleMethod(((MethodInsnNode) insn), perms, m, insn)\n                } else if (insn instanceof FieldInsnNode) {\n                    handleField(((FieldInsnNode) insn), perms)\n                } else if (insn instanceof InvokeDynamicInsnNode) {\n                    // no-op for now\n                }\n            }\n        }\n    }\n\n    private static void handleMethod(MethodInsnNode min, Set<String> perms, def methodNode, AbstractInsnNode current) {\n        String owner = min.owner\n        String name = min.name\n\n        if (owner.startsWith('java/net/') || owner.startsWith('javax/net/')) {\n            perms.add('NETWORK')\n        }\n        if (owner.startsWith('java/io/') || owner.startsWith('java/nio/file/')) {\n            if (owner == 'java/io/FileOutputStream' || owner == 'java/io/FileWriter' || owner == 'java/io/PrintWriter') {\n                perms.add('FILE_WRITE'); perms.add('FILE_READ')\n            } else if (owner == 'java/io/RandomAccessFile') {\n                String mode = findPreviousLdcString(methodNode, current, 8)\n                if ('r'.equals(mode)) {\n                    perms.add('FILE_READ')\n                } else {\n                    perms.add('FILE_WRITE'); perms.add('FILE_READ')\n                }\n            } else if (owner.startsWith('java/nio/file/Files')) {\n                if (name.startsWith('newOutputStream') || name.startsWith('write') || name.startsWith('create') || name.startsWith('delete')) {\n                    perms.add('FILE_WRITE')\n                } else if (name.startsWith('newInputStream') || name.startsWith('read')) {\n                    perms.add('FILE_READ')\n                }\n            } else if (owner == 'java/io/FileInputStream' || owner == 'java/io/BufferedInputStream' || owner == 'java/io/InputStreamReader') {\n                perms.add('FILE_READ')\n            }\n        }\n        if (owner == 'java/io/File') {\n            if (name in ['delete', 'deleteOnExit', 'renameTo', 'mkdir', 'mkdirs', 'createNewFile', 'setReadable', 'setWritable', 'setExecutable']) {\n                perms.add('FILE_WRITE')\n            }\n        }\n        if (owner == 'java/nio/file/Files') {\n            if (name in ['createFile','createDirectory','createDirectories','delete','deleteIfExists','move','setAttribute','setPosixFilePermissions','copy','write']) {\n                perms.add('FILE_WRITE')\n            }\n        }\n        if ((owner == 'java/nio/channels/FileChannel' || owner == 'java/nio/channels/AsynchronousFileChannel') && name == 'open') {\n            if (hasOpenOptionWrite(methodNode, current, 20)) {\n                perms.add('FILE_WRITE')\n            } else {\n                perms.add('FILE_READ')\n            }\n        }\n        if (owner == 'java/util/logging/FileHandler' && name == '<init>') {\n            perms.add('FILE_WRITE')\n        }\n        if (owner == 'java/lang/Thread' || owner.startsWith('java/util/concurrent/')) {\n            perms.add('THREADS')\n        }\n        if (owner == 'sun/misc/Unsafe' || owner == 'jdk/internal/misc/Unsafe') {\n            perms.add('NATIVE')\n        }\n        if (owner == 'java/lang/System' && (name == 'load' || name == 'loadLibrary')) {\n            perms.add('NATIVE')\n        }\n        if (owner == 'java/lang/Runtime' && name == 'exec') {\n            perms.add('EXEC')\n        }\n        if (owner == 'java/lang/ProcessBuilder' && name == '<init>') {\n            perms.add('EXEC')\n        }\n        if (owner.startsWith('java/lang/reflect/')) {\n            perms.add('REFLECTION')\n        }\n        if (owner == 'java/lang/ClassLoader' || owner == 'java/lang/Class' && name.startsWith('forName')) {\n            perms.add('CLASSLOADER')\n        }\n        if (owner == 'java/lang/System' && name == 'getProperty') {\n            perms.add('SYSTEM_PROPS')\n        }\n        if (owner == 'java/lang/management/ManagementFactory') {\n            perms.add('THREAD_INFO'); perms.add('MEMORY_INFO')\n        }\n        if (owner.startsWith('com/sun/management/')) {\n            perms.add('MEMORY_INFO')\n        }\n        if (owner.startsWith('jdk/jfr/') || owner.startsWith('org/openjdk/btrace/core/jfr/')) {\n            perms.add('JFR_EVENTS')\n        }\n    }\n\n    private static void handleField(FieldInsnNode fin, Set<String> perms) {\n        String owner = fin.owner\n        String name = fin.name\n        if (owner == 'java/lang/System' && name == 'props') {\n            perms.add('SYSTEM_PROPS')\n        }\n    }\n\n    private static String findPreviousLdcString(def methodNode, AbstractInsnNode from, int window) {\n        if (methodNode == null || from == null) return null\n        int count = 0\n        for (AbstractInsnNode p = from.previous; p != null && count < window; p = p.previous, count++) {\n            if (p.opcode == Opcodes.LDC && p instanceof LdcInsnNode) {\n                def cst = ((LdcInsnNode) p).cst\n                if (cst instanceof String) return (String) cst\n            }\n        }\n        return null\n    }\n\n    private static boolean hasOpenOptionWrite(def methodNode, AbstractInsnNode from, int window) {\n        if (methodNode == null || from == null) return true\n        int count = 0\n        for (AbstractInsnNode p = from.previous; p != null && count < window; p = p.previous, count++) {\n            if (p instanceof FieldInsnNode) {\n                FieldInsnNode fin = (FieldInsnNode) p\n                if (fin.owner == 'java/nio/file/StandardOpenOption') {\n                    if (['WRITE','APPEND','CREATE','CREATE_NEW','TRUNCATE_EXISTING','DELETE_ON_CLOSE'].contains(fin.name)) {\n                        return true\n                    }\n                }\n            }\n        }\n        return false\n    }\n\n    private static InputStream openClassStream(String internalName, List<File> sources) {\n        String entry = internalName.endsWith('.class') ? internalName : (internalName + '.class')\n        for (File f : sources) {\n            if (f.isDirectory()) {\n                File cf = new File(f, entry)\n                if (cf.exists()) return new FileInputStream(cf)\n            } else if (f.name.endsWith('.jar')) {\n                try {\n                    def zip = new ZipFile(f)\n                    def ze = zip.getEntry(entry)\n                    if (ze != null) {\n                        return zip.getInputStream(ze)\n                    } else {\n                        zip.close()\n                    }\n                } catch (IOException ignored) { }\n            }\n        }\n        return null\n    }\n}\n\n"
  },
  {
    "path": "btrace-instr/build.gradle",
    "content": "import java.nio.file.Files\nimport java.nio.file.Paths\n\nplugins {\n    id 'java'\n}\n\ndependencies {\n    implementation libs.slf4j\n    implementation libs.asm\n    implementation libs.asm.tree\n    implementation libs.asm.util\n    implementation libs.autoService\n    implementation libs.jctools\n    implementation project(':btrace-core')\n    implementation project(':btrace-extension')\n    implementation project(':btrace-runtime')\n    implementation project(':btrace-compiler')\n\n    testImplementation libs.asm.util\n    testImplementation libs.slf4j.simple\n    testImplementation libs.junit.jupiter\n    testImplementation project(':btrace-client')\n    testImplementation project(':btrace-extensions:btrace-statsd')\n    testImplementation project(':btrace-extensions:btrace-utils')\n}\n\ncompileJava {\n    javaCompiler = javaToolchains.compilerFor {\n        languageVersion.set(JavaLanguageVersion.of(8))\n    }\n}\n\ncompileTestJava {\n    options.fork = true\n    options.forkOptions.executable = \"${getJavac(8)}\"\n}\n\ntask compileTestProbes {\n    dependsOn compileTestJava, processTestResources\n    doLast {\n        def path = project(':btrace-instr').sourceSets.main.runtimeClasspath\n\n        def loader = new URLClassLoader(path.collect { f -> f.toURL() } as URL[])\n        def compiler = loader.loadClass('org.openjdk.btrace.compiler.Compiler')\n        // Use test runtime classpath so test-only extension APIs are available\n        def rtCp = sourceSets.test.runtimeClasspath\n\n        def extraCp = files(\n                buildDir.toPath().resolve(\"classes/java/test\"),\n                buildDir.toPath().resolve(\"classes/java/java11_dummy\"),\n                buildDir.toPath().resolve(\"resources/test\")\n        )\n        // Include extension API outputs explicitly to avoid jar task coupling\n        def utilsApi = project(':btrace-extensions:btrace-utils').sourceSets.api.output\n        def statsdApi = project(':btrace-extensions:btrace-statsd').sourceSets.api.output\n        def fullCp = rtCp.plus(extraCp).plus(utilsApi).plus(statsdApi)\n        def cpPath = fullCp.getAsPath()\n        def args = [\n                \"-cp\", cpPath,\n                \"-d\", buildDir.toPath().resolve(\"classes\")\n        ]\n\n        def files = fileTree(dir: \"src/test/btrace\", include: '**/*.java', exclude: 'verifier/**/*.java').findAll {\n            it != null\n        }.collect { it }\n\n        args.addAll(files)\n\n        // Help verifier discover extension services by exposing classpath to System property scanning\n        def oldCp = System.getProperty('java.class.path')\n        try {\n            System.setProperty('btrace.allow.undeclared.services', 'true')\n            System.setProperty('java.class.path', cpPath)\n            compiler.main(args as String[])\n        } finally {\n            if (oldCp != null) System.setProperty('java.class.path', oldCp)\n            System.clearProperty('btrace.allow.undeclared.services')\n        }\n    }\n}\n\ntest {\n    dependsOn cleanTest\n    inputs.files compileTestProbes.outputs\n    testLogging.showStandardStreams = true\n\n    def props = new Properties()\n    props.load(Files.newInputStream(Paths.get(System.getenv(\"JAVA_HOME\"), \"release\")))\n    if (!props.getProperty(\"JAVA_VERSION\")?.contains(\"1.8\")) {\n        jvmArgs '-XX:+IgnoreUnrecognizedVMOptions',\n                '--add-opens', 'java.base/java.lang=ALL-UNNAMED',\n                '--add-opens', 'java.base/jdk.internal.reflect=ALL-UNNAMED',\n                '--add-opens', 'java.base/java.lang=ALL-UNNAMED', '--add-exports', 'java.base/jdk.internal.reflect=ALL-UNNAMED'\n    }\n    if (project.hasProperty(\"updateTestData\")) {\n        jvmArgs '-Dupdate.test.data=true'\n    }\n    jvmArgs \"-Dtest.resources=${projectDir}/src/test/resources\"\n    jvmArgs \"-Dproject.version=${project.version}\"\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ArrayAccessInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Type;\n\n/**\n * This visitor helps in inserting code whenever an array access is done. Code to insert on array\n * access may be decided by derived class. By default, this class inserts code to print array\n * access.\n *\n * @author A. Sundararajan\n */\npublic class ArrayAccessInstrumentor extends MethodInstrumentor {\n  public ArrayAccessInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  public void visitInsn(int opcode) {\n    boolean arrayload = false;\n    boolean arraystore = false;\n    switch (opcode) {\n      case IALOAD:\n      case LALOAD:\n      case FALOAD:\n      case DALOAD:\n      case AALOAD:\n      case BALOAD:\n      case CALOAD:\n      case SALOAD:\n        arrayload = true;\n        break;\n\n      case IASTORE:\n      case LASTORE:\n      case FASTORE:\n      case DASTORE:\n      case AASTORE:\n      case BASTORE:\n      case CASTORE:\n      case SASTORE:\n        arraystore = true;\n        break;\n    }\n    if (arrayload) {\n      onBeforeArrayLoad(opcode);\n    } else if (arraystore) {\n      onBeforeArrayStore(opcode);\n    }\n    super.visitInsn(opcode);\n    if (arrayload) {\n      onAfterArrayLoad(opcode);\n    } else if (arraystore) {\n      onAfterArrayStore(opcode);\n    }\n  }\n\n  protected final boolean locationTypeMismatch(Location loc, Type arrtype, Type itemType) {\n    return !loc.getType().isEmpty()\n        && (!loc.getType().equals(arrtype.getClassName())\n            && !loc.getType().equals(itemType.getClassName()));\n  }\n\n  protected void onBeforeArrayLoad(int opcode) {}\n\n  protected void onAfterArrayLoad(int opcode) {}\n\n  protected void onBeforeArrayStore(int opcode) {}\n\n  protected void onAfterArrayStore(int opcode) {}\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ArrayAllocInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.ANEWARRAY;\nimport static org.objectweb.asm.Opcodes.NEWARRAY;\n\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * This visitor helps in inserting code whenever an array is allocated. The code to insert on method\n * entry may be decided by derived class. By default, this class inserts code to print allocated\n * array objects.\n *\n * @author A. Sundararajan\n */\npublic class ArrayAllocInstrumentor extends MethodInstrumentor {\n  public ArrayAllocInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  public void visitIntInsn(int opcode, int operand) {\n    String desc = null;\n    if (opcode == NEWARRAY) {\n      desc = InstrumentUtils.arrayDescriptorFor(operand);\n      onBeforeArrayNew(getPlainType(desc), 1);\n    }\n    super.visitIntInsn(opcode, operand);\n    if (opcode == NEWARRAY) {\n      onAfterArrayNew(getPlainType(desc), 1);\n    }\n  }\n\n  @Override\n  public void visitTypeInsn(int opcode, String desc) {\n    if (opcode == ANEWARRAY) {\n      onBeforeArrayNew(\"L\" + desc + \";\", 1);\n    }\n    super.visitTypeInsn(opcode, desc);\n    if (opcode == ANEWARRAY) {\n      onAfterArrayNew(\"L\" + desc + \";\", 1);\n    }\n  }\n\n  @Override\n  public void visitMultiANewArrayInsn(String desc, int dims) {\n    String type = getPlainType(desc);\n    onBeforeArrayNew(type, dims);\n    super.visitMultiANewArrayInsn(desc, dims);\n    onAfterArrayNew(type, dims);\n  }\n\n  protected void onBeforeArrayNew(String desc, int dims) {\n    asm.println(\"before allocating \" + desc);\n  }\n\n  protected void onAfterArrayNew(String desc, int dims) {\n    asm.dup().printObject();\n  }\n\n  private String getPlainType(String desc) {\n    int index = desc.lastIndexOf('[') + 1;\n    if (index > 0) {\n      return desc.substring(index);\n    }\n    return desc;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/Assembler.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.Handle;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Type;\nimport org.openjdk.btrace.runtime.Interval;\n\nimport static org.objectweb.asm.Opcodes.AALOAD;\nimport static org.objectweb.asm.Opcodes.AASTORE;\nimport static org.objectweb.asm.Opcodes.ACONST_NULL;\nimport static org.objectweb.asm.Opcodes.ANEWARRAY;\nimport static org.objectweb.asm.Opcodes.ARETURN;\nimport static org.objectweb.asm.Opcodes.BALOAD;\nimport static org.objectweb.asm.Opcodes.BASTORE;\nimport static org.objectweb.asm.Opcodes.BIPUSH;\nimport static org.objectweb.asm.Opcodes.CALOAD;\nimport static org.objectweb.asm.Opcodes.CASTORE;\nimport static org.objectweb.asm.Opcodes.CHECKCAST;\nimport static org.objectweb.asm.Opcodes.DALOAD;\nimport static org.objectweb.asm.Opcodes.DASTORE;\nimport static org.objectweb.asm.Opcodes.DCONST_0;\nimport static org.objectweb.asm.Opcodes.DRETURN;\nimport static org.objectweb.asm.Opcodes.DSUB;\nimport static org.objectweb.asm.Opcodes.DUP;\nimport static org.objectweb.asm.Opcodes.DUP2;\nimport static org.objectweb.asm.Opcodes.DUP2_X1;\nimport static org.objectweb.asm.Opcodes.DUP2_X2;\nimport static org.objectweb.asm.Opcodes.DUP_X1;\nimport static org.objectweb.asm.Opcodes.DUP_X2;\nimport static org.objectweb.asm.Opcodes.FALOAD;\nimport static org.objectweb.asm.Opcodes.FASTORE;\nimport static org.objectweb.asm.Opcodes.FCONST_0;\nimport static org.objectweb.asm.Opcodes.FRETURN;\nimport static org.objectweb.asm.Opcodes.FSUB;\nimport static org.objectweb.asm.Opcodes.GETFIELD;\nimport static org.objectweb.asm.Opcodes.GETSTATIC;\nimport static org.objectweb.asm.Opcodes.GOTO;\nimport static org.objectweb.asm.Opcodes.IALOAD;\nimport static org.objectweb.asm.Opcodes.IASTORE;\nimport static org.objectweb.asm.Opcodes.ICONST_0;\nimport static org.objectweb.asm.Opcodes.ICONST_1;\nimport static org.objectweb.asm.Opcodes.ICONST_2;\nimport static org.objectweb.asm.Opcodes.ICONST_3;\nimport static org.objectweb.asm.Opcodes.ICONST_4;\nimport static org.objectweb.asm.Opcodes.ICONST_5;\nimport static org.objectweb.asm.Opcodes.ICONST_M1;\nimport static org.objectweb.asm.Opcodes.IFNE;\nimport static org.objectweb.asm.Opcodes.IF_ICMPGT;\nimport static org.objectweb.asm.Opcodes.IF_ICMPLT;\nimport static org.objectweb.asm.Opcodes.ILOAD;\nimport static org.objectweb.asm.Opcodes.INVOKESPECIAL;\nimport static org.objectweb.asm.Opcodes.INVOKESTATIC;\nimport static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;\nimport static org.objectweb.asm.Opcodes.IRETURN;\nimport static org.objectweb.asm.Opcodes.ISTORE;\nimport static org.objectweb.asm.Opcodes.ISUB;\nimport static org.objectweb.asm.Opcodes.LALOAD;\nimport static org.objectweb.asm.Opcodes.LASTORE;\nimport static org.objectweb.asm.Opcodes.LCONST_0;\nimport static org.objectweb.asm.Opcodes.LCONST_1;\nimport static org.objectweb.asm.Opcodes.LRETURN;\nimport static org.objectweb.asm.Opcodes.LSUB;\nimport static org.objectweb.asm.Opcodes.NEW;\nimport static org.objectweb.asm.Opcodes.POP;\nimport static org.objectweb.asm.Opcodes.PUTFIELD;\nimport static org.objectweb.asm.Opcodes.PUTSTATIC;\nimport static org.objectweb.asm.Opcodes.RETURN;\nimport static org.objectweb.asm.Opcodes.SALOAD;\nimport static org.objectweb.asm.Opcodes.SASTORE;\nimport static org.objectweb.asm.Opcodes.SIPUSH;\nimport static org.objectweb.asm.Opcodes.SWAP;\nimport static org.openjdk.btrace.instr.Constants.BOOLEAN_BOXED_INTERNAL;\nimport static org.openjdk.btrace.instr.Constants.BOOLEAN_VALUE;\nimport static org.openjdk.btrace.instr.Constants.BOOLEAN_VALUE_DESC;\nimport static org.openjdk.btrace.instr.Constants.BOX_BOOLEAN_DESC;\nimport static org.openjdk.btrace.instr.Constants.BOX_BYTE_DESC;\nimport static org.openjdk.btrace.instr.Constants.BOX_CHARACTER_DESC;\nimport static org.openjdk.btrace.instr.Constants.BOX_DOUBLE_DESC;\nimport static org.openjdk.btrace.instr.Constants.BOX_FLOAT_DESC;\nimport static org.openjdk.btrace.instr.Constants.BOX_INTEGER_DESC;\nimport static org.openjdk.btrace.instr.Constants.BOX_LONG_DESC;\nimport static org.openjdk.btrace.instr.Constants.BOX_SHORT_DESC;\nimport static org.openjdk.btrace.instr.Constants.BOX_VALUEOF;\nimport static org.openjdk.btrace.instr.Constants.BTRACE_LEVEL_FLD;\nimport static org.openjdk.btrace.instr.Constants.BYTE_BOXED_INTERNAL;\nimport static org.openjdk.btrace.instr.Constants.BYTE_VALUE;\nimport static org.openjdk.btrace.instr.Constants.BYTE_VALUE_DESC;\nimport static org.openjdk.btrace.instr.Constants.CHARACTER_BOXED_INTERNAL;\nimport static org.openjdk.btrace.instr.Constants.CHAR_VALUE;\nimport static org.openjdk.btrace.instr.Constants.CHAR_VALUE_DESC;\nimport static org.openjdk.btrace.instr.Constants.DOUBLE_BOXED_INTERNAL;\nimport static org.openjdk.btrace.instr.Constants.DOUBLE_VALUE;\nimport static org.openjdk.btrace.instr.Constants.DOUBLE_VALUE_DESC;\nimport static org.openjdk.btrace.instr.Constants.FLOAT_BOXED_INTERNAL;\nimport static org.openjdk.btrace.instr.Constants.FLOAT_VALUE;\nimport static org.openjdk.btrace.instr.Constants.FLOAT_VALUE_DESC;\nimport static org.openjdk.btrace.instr.Constants.INTEGER_BOXED_INTERNAL;\nimport static org.openjdk.btrace.instr.Constants.INT_DESC;\nimport static org.openjdk.btrace.instr.Constants.INT_VALUE;\nimport static org.openjdk.btrace.instr.Constants.INT_VALUE_DESC;\nimport static org.openjdk.btrace.instr.Constants.LONG_BOXED_INTERNAL;\nimport static org.openjdk.btrace.instr.Constants.LONG_VALUE;\nimport static org.openjdk.btrace.instr.Constants.LONG_VALUE_DESC;\nimport static org.openjdk.btrace.instr.Constants.NUMBER_INTERNAL;\nimport static org.openjdk.btrace.instr.Constants.SHORT_BOXED_INTERNAL;\nimport static org.openjdk.btrace.instr.Constants.SHORT_VALUE;\nimport static org.openjdk.btrace.instr.Constants.SHORT_VALUE_DESC;\n\n/**\n * Convenient fluent wrapper over the ASM method visitor\n *\n * @author Jaroslav Bachorik\n */\n@SuppressWarnings(\"UnusedReturnValue\")\npublic final class Assembler {\n  private final MethodVisitor mv;\n  private final MethodInstrumentorHelper mHelper;\n\n  public Assembler(MethodVisitor mv, MethodInstrumentorHelper mHelper) {\n    this.mv = mv;\n    this.mHelper = mHelper;\n  }\n\n  public Assembler push(int value) {\n    if (value >= -1 && value <= 5) {\n      mv.visitInsn(ICONST_0 + value);\n    } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {\n      mv.visitIntInsn(BIPUSH, value);\n    } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {\n      mv.visitIntInsn(SIPUSH, value);\n    } else {\n      mv.visitLdcInsn(value);\n    }\n    return this;\n  }\n\n  public Assembler arrayLoad(Type type) {\n    mv.visitInsn(type.getOpcode(IALOAD));\n    return this;\n  }\n\n  public Assembler arrayStore(Type type) {\n    mv.visitInsn(type.getOpcode(IASTORE));\n    return this;\n  }\n\n  public Assembler jump(int opcode, Label l) {\n    mv.visitJumpInsn(opcode, l);\n    return this;\n  }\n\n  public Assembler ldc(Object o) {\n    if (o == null) {\n      return loadNull();\n    }\n    if (o instanceof Integer) {\n      int i = (int) o;\n      if (i >= -1 && i <= 5) {\n        int opcode = -1;\n        switch (i) {\n          case 0:\n            {\n              opcode = ICONST_0;\n              break;\n            }\n          case 1:\n            {\n              opcode = ICONST_1;\n              break;\n            }\n          case 2:\n            {\n              opcode = ICONST_2;\n              break;\n            }\n          case 3:\n            {\n              opcode = ICONST_3;\n              break;\n            }\n          case 4:\n            {\n              opcode = ICONST_4;\n              break;\n            }\n          case 5:\n            {\n              opcode = ICONST_5;\n              break;\n            }\n          case -1:\n            {\n              opcode = ICONST_M1;\n              break;\n            }\n        }\n        mv.visitInsn(opcode);\n        return this;\n      }\n    }\n    if (o instanceof Long) {\n      long l = (long) o;\n      if (l >= 0 && l <= 1) {\n        int opcode = -1;\n        switch ((int) l) {\n          case 0:\n            {\n              opcode = LCONST_0;\n              break;\n            }\n          case 1:\n            {\n              opcode = LCONST_1;\n              break;\n            }\n        }\n        mv.visitInsn(opcode);\n        return this;\n      }\n    }\n    mv.visitLdcInsn(o);\n    return this;\n  }\n\n  public Assembler sub(Type t) {\n    int opcode = -1;\n    switch (t.getSort()) {\n      case Type.SHORT:\n      case Type.BYTE:\n      case Type.INT:\n        {\n          opcode = ISUB;\n          break;\n        }\n      case Type.LONG:\n        {\n          opcode = LSUB;\n          break;\n        }\n      case Type.FLOAT:\n        {\n          opcode = FSUB;\n          break;\n        }\n      case Type.DOUBLE:\n        {\n          opcode = DSUB;\n          break;\n        }\n    }\n    if (opcode != -1) {\n      mv.visitInsn(opcode);\n    }\n    return this;\n  }\n\n  public Assembler loadNull() {\n    mv.visitInsn(ACONST_NULL);\n    return this;\n  }\n\n  public Assembler loadLocal(Type type, int index) {\n    mv.visitVarInsn(type.getOpcode(ILOAD), index);\n    return this;\n  }\n\n  public Assembler storeLocal(Type type, int index) {\n    mv.visitVarInsn(type.getOpcode(ISTORE), index);\n    return this;\n  }\n\n  public Assembler storeField(Type owner, String name, Type t) {\n    mv.visitFieldInsn(PUTFIELD, owner.getInternalName(), name, t.getDescriptor());\n    return this;\n  }\n\n  public Assembler storeStaticField(Type owner, String name, Type t) {\n    mv.visitFieldInsn(PUTSTATIC, owner.getInternalName(), name, t.getDescriptor());\n    return this;\n  }\n\n  public Assembler loadField(Type owner, String name, Type t) {\n    mv.visitFieldInsn(GETFIELD, owner.getInternalName(), name, t.getDescriptor());\n    return this;\n  }\n\n  public Assembler loadStaticField(Type owner, String name, Type t) {\n    mv.visitFieldInsn(GETSTATIC, owner.getInternalName(), name, t.getDescriptor());\n    return this;\n  }\n\n  public Assembler pop() {\n    mv.visitInsn(POP);\n    return this;\n  }\n\n  public Assembler dup() {\n    mv.visitInsn(DUP);\n    return this;\n  }\n\n  public Assembler dup_x1() {\n    mv.visitInsn(DUP_X1);\n    return this;\n  }\n\n  public Assembler dup_x2() {\n    mv.visitInsn(DUP_X2);\n    return this;\n  }\n\n  public Assembler dup2() {\n    mv.visitInsn(DUP2);\n    return this;\n  }\n\n  public Assembler dup2_x1() {\n    mv.visitInsn(DUP2_X1);\n    return this;\n  }\n\n  public Assembler dup2_x2() {\n    mv.visitInsn(DUP2_X2);\n    return this;\n  }\n\n  public Assembler swap() {\n    mv.visitInsn(SWAP);\n    return this;\n  }\n\n  public Assembler newInstance(Type t) {\n    mv.visitTypeInsn(NEW, t.getInternalName());\n    return this;\n  }\n\n  public Assembler newArray(Type t) {\n    mv.visitTypeInsn(ANEWARRAY, t.getInternalName());\n    return this;\n  }\n\n  public Assembler dupArrayValue(int arrayOpcode) {\n    switch (arrayOpcode) {\n      case IALOAD:\n      case FALOAD:\n      case AALOAD:\n      case BALOAD:\n      case CALOAD:\n      case SALOAD:\n      case IASTORE:\n      case FASTORE:\n      case AASTORE:\n      case BASTORE:\n      case CASTORE:\n      case SASTORE:\n        dup();\n        break;\n\n      case LALOAD:\n      case DALOAD:\n      case LASTORE:\n      case DASTORE:\n        dup2();\n        break;\n    }\n    return this;\n  }\n\n  public Assembler dupReturnValue(int returnOpcode) {\n    switch (returnOpcode) {\n      case IRETURN:\n      case FRETURN:\n      case ARETURN:\n        mv.visitInsn(DUP);\n        break;\n      case LRETURN:\n      case DRETURN:\n        mv.visitInsn(DUP2);\n        break;\n      case RETURN:\n        break;\n      default:\n        throw new IllegalArgumentException(\"not return\");\n    }\n    return this;\n  }\n\n  public Assembler dupValue(Type type) {\n    switch (type.getSize()) {\n      case 1:\n        dup();\n        break;\n      case 2:\n        dup2();\n        break;\n    }\n    return this;\n  }\n\n  public Assembler dupValue(String desc) {\n    int typeCode = desc.charAt(0);\n    switch (typeCode) {\n      case '[':\n      case 'L':\n      case 'Z':\n      case 'C':\n      case 'B':\n      case 'S':\n      case 'I':\n        mv.visitInsn(DUP);\n        break;\n      case 'J':\n      case 'D':\n        mv.visitInsn(DUP2);\n        break;\n      default:\n        throw new InstrumentationException(\n            String.format(\"Invalid bytecode signature in dupValue: %s\", desc));\n    }\n    return this;\n  }\n\n  public Assembler box(Type type) {\n    return box(type.getDescriptor());\n  }\n\n  public Assembler box(String desc) {\n    int typeCode = desc.charAt(0);\n    switch (typeCode) {\n      case '[':\n      case 'L':\n        break;\n      case 'Z':\n        invokeStatic(BOOLEAN_BOXED_INTERNAL, BOX_VALUEOF, BOX_BOOLEAN_DESC);\n        break;\n      case 'C':\n        invokeStatic(CHARACTER_BOXED_INTERNAL, BOX_VALUEOF, BOX_CHARACTER_DESC);\n        break;\n      case 'B':\n        invokeStatic(BYTE_BOXED_INTERNAL, BOX_VALUEOF, BOX_BYTE_DESC);\n        break;\n      case 'S':\n        invokeStatic(SHORT_BOXED_INTERNAL, BOX_VALUEOF, BOX_SHORT_DESC);\n        break;\n      case 'I':\n        invokeStatic(INTEGER_BOXED_INTERNAL, BOX_VALUEOF, BOX_INTEGER_DESC);\n        break;\n      case 'J':\n        invokeStatic(LONG_BOXED_INTERNAL, BOX_VALUEOF, BOX_LONG_DESC);\n        break;\n      case 'F':\n        invokeStatic(FLOAT_BOXED_INTERNAL, BOX_VALUEOF, BOX_FLOAT_DESC);\n        break;\n      case 'D':\n        invokeStatic(DOUBLE_BOXED_INTERNAL, BOX_VALUEOF, BOX_DOUBLE_DESC);\n        break;\n    }\n    return this;\n  }\n\n  public Assembler unbox(Type type) {\n    return unbox(type.getDescriptor());\n  }\n\n  public Assembler unbox(String desc) {\n    int typeCode = desc.charAt(0);\n    switch (typeCode) {\n      case '[':\n      case 'L':\n        mv.visitTypeInsn(CHECKCAST, Type.getType(desc).getInternalName());\n        break;\n      case 'Z':\n        mv.visitTypeInsn(CHECKCAST, BOOLEAN_BOXED_INTERNAL);\n        invokeVirtual(BOOLEAN_BOXED_INTERNAL, BOOLEAN_VALUE, BOOLEAN_VALUE_DESC);\n        break;\n      case 'C':\n        mv.visitTypeInsn(CHECKCAST, CHARACTER_BOXED_INTERNAL);\n        invokeVirtual(CHARACTER_BOXED_INTERNAL, CHAR_VALUE, CHAR_VALUE_DESC);\n        break;\n      case 'B':\n        mv.visitTypeInsn(CHECKCAST, NUMBER_INTERNAL);\n        invokeVirtual(NUMBER_INTERNAL, BYTE_VALUE, BYTE_VALUE_DESC);\n        break;\n      case 'S':\n        mv.visitTypeInsn(CHECKCAST, NUMBER_INTERNAL);\n        invokeVirtual(NUMBER_INTERNAL, SHORT_VALUE, SHORT_VALUE_DESC);\n        break;\n      case 'I':\n        mv.visitTypeInsn(CHECKCAST, NUMBER_INTERNAL);\n        invokeVirtual(NUMBER_INTERNAL, INT_VALUE, INT_VALUE_DESC);\n        break;\n      case 'J':\n        mv.visitTypeInsn(CHECKCAST, NUMBER_INTERNAL);\n        invokeVirtual(NUMBER_INTERNAL, LONG_VALUE, LONG_VALUE_DESC);\n        break;\n      case 'F':\n        mv.visitTypeInsn(CHECKCAST, NUMBER_INTERNAL);\n        invokeVirtual(NUMBER_INTERNAL, FLOAT_VALUE, FLOAT_VALUE_DESC);\n        break;\n      case 'D':\n        mv.visitTypeInsn(CHECKCAST, NUMBER_INTERNAL);\n        invokeVirtual(NUMBER_INTERNAL, DOUBLE_VALUE, DOUBLE_VALUE_DESC);\n        break;\n    }\n    return this;\n  }\n\n  public Assembler defaultValue(String desc) {\n    int typeCode = desc.charAt(0);\n    switch (typeCode) {\n      case '[':\n      case 'L':\n        mv.visitInsn(ACONST_NULL);\n        break;\n      case 'Z':\n      case 'C':\n      case 'B':\n      case 'S':\n      case 'I':\n        mv.visitInsn(ICONST_0);\n        break;\n      case 'J':\n        mv.visitInsn(LCONST_0);\n        break;\n      case 'F':\n        mv.visitInsn(FCONST_0);\n        break;\n      case 'D':\n        mv.visitInsn(DCONST_0);\n        break;\n    }\n    return this;\n  }\n\n  public Assembler println(String msg) {\n    mv.visitFieldInsn(GETSTATIC, \"java/lang/System\", \"out\", \"Ljava/io/PrintStream;\");\n    mv.visitLdcInsn(msg);\n    invokeVirtual(\"java/io/PrintStream\", \"println\", \"(Ljava/lang/String;)V\");\n    return this;\n  }\n\n  // print the object on the top of the stack\n  public Assembler printObject() {\n    mv.visitFieldInsn(GETSTATIC, \"java/lang/System\", \"out\", \"Ljava/io/PrintStream;\");\n    mv.visitInsn(SWAP);\n    mv.visitMethodInsn(\n        INVOKEVIRTUAL, \"java/io/PrintStream\", \"println\", \"(Ljava/lang/Object;)V\", false);\n    return this;\n  }\n\n  public Assembler invokeVirtual(String owner, String method, String desc) {\n    mv.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc, false);\n    return this;\n  }\n\n  public Assembler invokeSpecial(String owner, String method, String desc) {\n    mv.visitMethodInsn(INVOKESPECIAL, owner, method, desc, false);\n    return this;\n  }\n\n  public Assembler invokeStatic(String owner, String method, String desc) {\n    mv.visitMethodInsn(INVOKESTATIC, owner, method, desc, false);\n    return this;\n  }\n\n  public Assembler invokeDynamic(\n      String name, String descriptor, Handle bootstrap, Object... bootstrapArguments) {\n    mv.visitInvokeDynamicInsn(name, descriptor, bootstrap, bootstrapArguments);\n    return this;\n  }\n\n  public Assembler invokeInterface(String owner, String method, String desc) {\n    mv.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc, true);\n    return this;\n  }\n\n  public Assembler getStatic(String owner, String name, String desc) {\n    mv.visitFieldInsn(GETSTATIC, owner, name, desc);\n    return this;\n  }\n\n  public Assembler putStatic(String owner, String name, String desc) {\n    mv.visitFieldInsn(PUTSTATIC, owner, name, desc);\n    return this;\n  }\n\n  public Assembler label(Label l) {\n    mv.visitLabel(l);\n    return this;\n  }\n\n  public Assembler addLevelCheck(String clsName, Level level, Label jmp) {\n    return addLevelCheck(clsName, level.getValue(), jmp);\n  }\n\n  public Assembler addLevelCheck(String clsName, Interval itv, Label jmp) {\n    getStatic(clsName, \"$btrace$$level\", INT_DESC);\n    if (itv.getA() <= 0) {\n      if (itv.getB() != Integer.MAX_VALUE) {\n        ldc(itv.getB());\n        jump(IF_ICMPGT, jmp);\n      }\n    } else if (itv.getA() < itv.getB()) {\n      if (itv.getB() == Integer.MAX_VALUE) {\n        ldc(itv.getA());\n        jump(IF_ICMPLT, jmp);\n      } else {\n        ldc(itv.getA());\n        jump(IF_ICMPLT, jmp);\n        getStatic(clsName, \"$btrace$$level\", INT_DESC);\n        ldc(itv.getB());\n        jump(IF_ICMPGT, jmp);\n      }\n    }\n    return this;\n  }\n\n  /**\n   * Compares the instrumentation level interval against the runtime value.\n   *\n   * <p>If the runtime value is fitting the level interval there will be 0 on stack upon return from\n   * this method. Otherwise there will be -1.\n   *\n   * @param clsName The probe class name\n   * @param level The probe instrumentation level\n   * @return itself\n   */\n  public Assembler compareLevel(String clsName, Level level) {\n    Interval itv = level.getValue();\n    if (itv.getA() <= 0) {\n      if (itv.getB() != Integer.MAX_VALUE) {\n        ldc(itv.getB());\n        getStatic(clsName, BTRACE_LEVEL_FLD, INT_DESC);\n        sub(Type.INT_TYPE);\n      }\n    } else if (itv.getA() < itv.getB()) {\n      if (itv.getB() == Integer.MAX_VALUE) {\n        getStatic(clsName, BTRACE_LEVEL_FLD, INT_DESC);\n        ldc(itv.getA());\n        sub(Type.INT_TYPE);\n      } else {\n        Label l1 = new Label();\n        Label l2 = new Label();\n        ldc(itv.getA());\n        jump(IF_ICMPLT, l1);\n        getStatic(clsName, BTRACE_LEVEL_FLD, INT_DESC);\n        ldc(itv.getB());\n        jump(IF_ICMPGT, l1);\n        ldc(0);\n        Label l3 = new Label();\n        label(l3);\n        mHelper.insertFrameSameStack(l3);\n        jump(GOTO, l2);\n        label(l1);\n        mHelper.insertFrameSameStack(l1);\n        ldc(-1);\n        label(l2);\n        mHelper.insertFrameSameStack(l2);\n      }\n    }\n    return this;\n  }\n\n  public Label openLinkerCheck() {\n    Label l = new Label();\n    invokeStatic(Constants.LINKING_FLAG_INTERNAL, \"get\", \"()I\");\n    // if the linking flag is 0, then we are not in a reentrant call\n    jump(IFNE, l);\n    return l;\n  }\n\n  public void closeLinkerCheck(Label l) {\n    label(l);\n    mHelper.insertFrameSameStack(l);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceBCPClassLoader.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport java.io.File;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nfinal class BTraceBCPClassLoader extends URLClassLoader {\n  private static final Logger log = LoggerFactory.getLogger(BTraceBCPClassLoader.class);\n\n  BTraceBCPClassLoader(SharedSettings settings) {\n    super(getBCPUrls(settings), null);\n  }\n\n  private static URL[] getBCPUrls(SharedSettings settings) {\n    String bcp = settings.getBootClassPath();\n    if (bcp != null && !bcp.isEmpty()) {\n      List<URL> urls = new ArrayList<>();\n      for (String cpElement : bcp.split(File.pathSeparator)) {\n        try {\n          urls.add(new File(cpElement).toURI().toURL());\n        } catch (MalformedURLException e) {\n          log.debug(\"Invalid classpath definition: {}\", cpElement, e);\n        }\n      }\n      return urls.toArray(new URL[0]);\n    }\n    return new URL[0];\n  }\n\n  @Override\n  public Class<?> loadClass(String name) throws ClassNotFoundException {\n    // delegate class loading to parent directly\n    ClassLoader parent = getParent();\n    if (parent == null) {\n      parent = ClassLoader.getSystemClassLoader();\n    }\n    return parent.loadClass(name);\n  }\n\n  @Override\n  public URL getResource(String name) {\n    // follow the standard process to load resources\n    return super.getResource(name);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceClassReader.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport org.objectweb.asm.AnnotationVisitor;\nimport org.objectweb.asm.Attribute;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A hacked version of <a\n * href=\"http://asm.ow2.org/asm50/javadoc/user/org/objectweb/asm/ClassReader.html\">ClassReader</a>\n * allowing fast access to class name, class version, super type, interfaces and annotations.\n *\n * @author Jaroslav Bachorik\n */\nfinal class BTraceClassReader extends ClassReader {\n  private static final Logger log = LoggerFactory.getLogger(BTraceClassReader.class);\n\n  private static final Method getAttributesMthd;\n  private static final Method readAnnotationValuesMthd;\n  private static final Field itemsFld;\n  private static final Field mslFld;\n\n  static {\n    Method m1 = null, m2 = null;\n    Field f1 = null, f2 = null;\n\n    try {\n      m1 = ClassReader.class.getDeclaredMethod(\"getFirstAttributeOffset\");\n      m1.setAccessible(true);\n\n      m2 =\n          ClassReader.class.getDeclaredMethod(\n              \"readElementValue\", AnnotationVisitor.class, int.class, String.class, char[].class);\n      m2.setAccessible(true);\n\n      f1 = ClassReader.class.getDeclaredField(\"cpInfoOffsets\");\n      f1.setAccessible(true);\n\n      f2 = ClassReader.class.getDeclaredField(\"maxStringLength\");\n      f2.setAccessible(true);\n    } catch (Exception e) {\n      log.debug(\"Failed to initialize BTraceClassReader reflection fields\", e);\n    }\n    getAttributesMthd = m1;\n    readAnnotationValuesMthd = m2;\n    itemsFld = f1;\n    mslFld = f2;\n  }\n\n  private final ClassLoader cl;\n\n  BTraceClassReader(ClassLoader cl, byte[] bytes) {\n    super(bytes);\n    this.cl = cl;\n  }\n\n  BTraceClassReader(ClassLoader cl, InputStream in) throws IOException {\n    super(in);\n    this.cl = cl;\n  }\n\n  public static void bailout() {\n    throw BailoutException.INSTANCE;\n  }\n\n  public ClassLoader getClassLoader() {\n    return cl;\n  }\n\n  /**\n   * The associated Java class name ('.' is the package delimiter)\n   *\n   * @return\n   */\n  public String getJavaClassName() {\n    return getClassName().replace('/', '.');\n  }\n\n  public String[] readClassSupers() {\n    String[] ifaces = getInterfaces();\n    String[] supers = Arrays.copyOf(ifaces, ifaces.length + 1);\n    supers[supers.length - 1] = getSuperName();\n    return supers;\n  }\n\n  public boolean isInterface() {\n    return (getAccess() & Opcodes.ACC_INTERFACE) != 0;\n  }\n\n  public boolean isBTrace() {\n    return getAnnotationTypes().contains(Constants.BTRACE_DESC);\n  }\n\n  public Collection<String> getAnnotationTypes() {\n    Collection<String> types = new HashSet<>();\n\n    char[] c = new char[getMaxStringLength()]; // buffer used to read strings\n    int anns = getAnnotationsOffset(c);\n    if (anns != -1) {\n      for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {\n        types.add(Type.getType(readUTF8(v, c)).getClassName());\n        v = skipAnnotationValues(v + 2, c);\n        if (v == -1) break;\n      }\n    }\n    return types;\n  }\n\n  public int getClassVersion() {\n    try {\n      if (itemsFld != null) {\n        int[] items = (int[]) itemsFld.get(this);\n        return readInt(items[1] - 7);\n      }\n    } catch (Exception e) {\n      log.debug(\"Failed to read class major version\", e);\n    }\n    return 51; // default to Java 7\n  }\n\n  @Override\n  public void accept(ClassVisitor cv, Attribute[] atrbts, int i) {\n    try {\n      super.accept(cv, atrbts, i);\n    } catch (BailoutException e) {\n      // expected; ignore\n    }\n  }\n\n  @Override\n  public void accept(ClassVisitor cv, int i) {\n    try {\n      super.accept(cv, i);\n    } catch (BailoutException e) {\n      // expected; ignore\n    }\n  }\n\n  private int getAttributes() {\n    try {\n      if (getAttributesMthd != null) {\n        return (int) getAttributesMthd.invoke(this);\n      }\n    } catch (Exception e) {\n      log.debug(\"Failed to get first attribute offset\", e);\n    }\n    return -1;\n  }\n\n  private int getAnnotationsOffset(char[] buf) {\n    int u = getAttributes();\n    if (u == -1) {\n      return -1;\n    }\n    for (int i = readUnsignedShort(u - 2); i > 0; --i) {\n      String attrName = readUTF8(u, buf);\n      int attributeLength = readInt(u + 2);\n      u += 6;\n      if (\"RuntimeVisibleAnnotations\".equals(attrName)) {\n        return u;\n      }\n      u += attributeLength;\n    }\n    return -1;\n  }\n\n  private int skipAnnotationValues(int off, char[] buf) {\n    try {\n      if (readAnnotationValuesMthd != null) {\n        return (int) readAnnotationValuesMthd.invoke(this, null, off, null, buf);\n      }\n    } catch (Exception e) {\n      log.debug(\"Failed to read annotation values\", e);\n    }\n    return -1;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceClassWriter.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport java.util.ArrayDeque;\nimport java.util.Deque;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.ClassWriter;\nimport org.objectweb.asm.Opcodes;\n\n/**\n * A hacked version of <a\n * href=\"http://asm.ow2.org/asm50/javadoc/user/org/objectweb/asm/ClassWriter.html\">ClassWriter</a>\n * allowing to plug-in instrumentation providers and instrument class in single invocation. Also, it\n * provides a smart and lightweight common supertype resolution method for computing frames.\n *\n * <p>The class is not thread-safe but since there is exactly one instance per instrumented class\n * there is no chance of parallel access ever happening.\n *\n * @author Jaroslav Bachorik\n */\nfinal class BTraceClassWriter extends ClassWriter {\n  private final Deque<Instrumentor> instrumentors = new ArrayDeque<>();\n  private final ClassLoader targetCL;\n  private final BTraceClassReader cr;\n\n  BTraceClassWriter(ClassLoader cl, int flags) {\n    super(flags);\n    targetCL = cl != null ? cl : ClassLoader.getSystemClassLoader();\n    cr = null;\n  }\n\n  BTraceClassWriter(ClassLoader cl, BTraceClassReader reader, int flags) {\n    super(reader, flags);\n    targetCL = cl != null ? cl : ClassLoader.getSystemClassLoader();\n    cr = reader;\n  }\n\n  public void addInstrumentor(BTraceProbe bp) {\n    addInstrumentor(bp, null);\n  }\n\n  public void addInstrumentor(BTraceProbe bp, ClassLoader cl) {\n    if (cr != null && bp != null) {\n      Instrumentor top = instrumentors.peekLast();\n      ClassVisitor parent = top != null ? top : this;\n      Instrumentor i = Instrumentor.create(cr, bp, parent, cl);\n      if (i != null) {\n        instrumentors.add(i);\n      }\n    }\n  }\n\n  public byte[] instrument() {\n    boolean hit = false;\n    if (instrumentors.isEmpty()) return null;\n\n    Instrumentor top = instrumentors.peekLast();\n    ClassVisitor cv = top != null ? top : this;\n    InstrumentUtils.accept(cr, cv);\n    for (Instrumentor i : instrumentors) {\n      hit |= i.hasMatch();\n    }\n    return hit ? toByteArray() : null;\n  }\n\n  @Override\n  protected String getCommonSuperClass(String type1, String type2) {\n    // Using type closures resolved via the associate classloader\n    LinkedHashSet<String> type1Closure = new LinkedHashSet<>();\n    LinkedHashSet<String> type2Closure = new LinkedHashSet<>();\n    InstrumentUtils.collectHierarchyClosure(targetCL, type1, type1Closure, true);\n    InstrumentUtils.collectHierarchyClosure(targetCL, type2, type2Closure, true);\n    // basically, do intersection\n    type1Closure.retainAll(type2Closure);\n\n    // if the intersection is not empty the first element is the closest common ancestor\n    Iterator<String> iter = type1Closure.iterator();\n    if (iter.hasNext()) {\n      return iter.next();\n    }\n    return Constants.OBJECT_INTERNAL;\n  }\n\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceMethodNode.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.AnnotationVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.tree.MethodNode;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Where;\n\nimport java.util.Comparator;\nimport java.util.Set;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic class BTraceMethodNode extends MethodNode {\n  public static final Comparator<MethodNode> COMPARATOR =\n      (o1, o2) -> (o1.name + \"#\" + o1.desc).compareTo(o2.name + \"#\" + o2.desc);\n  private final BTraceProbeNode cn;\n  private final CallGraph graph;\n  private final String methodId;\n  private OnMethod om;\n  private OnProbe op;\n  private Location loc;\n  private boolean sampled;\n  private boolean isBTraceHandler;\n\n  BTraceMethodNode(MethodNode from, BTraceProbeNode cn) {\n    this(from, cn, false);\n  }\n\n  BTraceMethodNode(MethodNode from, BTraceProbeNode cn, boolean initBTraceHandler) {\n    super(\n        Opcodes.ASM9,\n        from.access,\n        from.name,\n        from.desc,\n        from.signature,\n        from.exceptions.toArray(new String[0]));\n    this.cn = cn;\n    graph = cn.getGraph();\n    methodId = CallGraph.methodId(name, desc);\n    isBTraceHandler = initBTraceHandler;\n  }\n\n  @Override\n  public void visitEnd() {\n    if (om != null) {\n      verifySpecialParameters(om);\n      cn.addOnMethod(om);\n    }\n    if (op != null) {\n      cn.addOnProbe(op);\n    }\n    if (isBTraceHandler) {\n      graph.addStarting(methodId);\n    }\n    super.visitEnd();\n  }\n\n  @Override\n  public AnnotationVisitor visitAnnotation(String type, boolean visible) {\n    AnnotationVisitor av = super.visitAnnotation(type, visible);\n\n    if (type.startsWith(\"Lorg/openjdk/btrace/core/annotations/\")) {\n      isBTraceHandler = true;\n    }\n    if (type.equals(Constants.ONMETHOD_DESC)) {\n      om = new OnMethod(this);\n      om.setTargetName(name);\n      om.setTargetDescriptor(desc);\n      return new AnnotationVisitor(Opcodes.ASM9, av) {\n        @Override\n        public void visit(String name, Object value) {\n          super.visit(name, value);\n\n          switch (name) {\n            case \"clazz\":\n              om.setClazz((String) value);\n              break;\n            case \"method\":\n              om.setMethod((String) value);\n              break;\n            case \"type\":\n              om.setType((String) value);\n              break;\n            case \"exactTypeMatch\":\n              {\n                om.setExactTypeMatch((boolean) value);\n                break;\n              }\n            default:\n              System.err.println(\"btrace WARNING: Unsupported @OnMethod attribute: \" + name);\n          }\n        }\n\n        @Override\n        public AnnotationVisitor visitAnnotation(String name, String desc) {\n          AnnotationVisitor av1 = super.visitAnnotation(name, desc);\n          if (desc.equals(Constants.LOCATION_DESC)) {\n            loc = new Location();\n            return new AnnotationVisitor(Opcodes.ASM9, av1) {\n              @Override\n              public void visitEnum(String name, String desc, String value) {\n                super.visitEnum(name, desc, value);\n\n                if (desc.equals(Constants.WHERE_DESC)) {\n                  loc.setWhere(Enum.valueOf(Where.class, value));\n                } else if (desc.equals(Constants.KIND_DESC)) {\n                  loc.setValue(Enum.valueOf(Kind.class, value));\n                }\n              }\n\n              @Override\n              public void visit(String name, Object value) {\n                super.visit(name, value);\n\n                switch (name) {\n                  case \"clazz\":\n                    loc.setClazz((String) value);\n                    break;\n                  case \"method\":\n                    loc.setMethod((String) value);\n                    break;\n                  case \"type\":\n                    loc.setType((String) value);\n                    break;\n                  case \"field\":\n                    loc.setField((String) value);\n                    break;\n                  case \"line\":\n                    loc.setLine(((Number) value).intValue());\n                    break;\n                }\n              }\n\n              @Override\n              public void visitEnd() {\n                if (loc != null) {\n                  om.setLocation(loc);\n                }\n                super.visitEnd();\n              }\n            };\n          } else if (desc.equals(Constants.LEVEL_DESC)) {\n            return new AnnotationVisitor(Opcodes.ASM9, av1) {\n              @Override\n              public void visit(String name, Object value) {\n                super.visit(name, value);\n\n                if (\"value\".equals(name)) {\n                  om.setLevel(Level.fromString((String) value));\n                }\n              }\n            };\n          }\n          return av1;\n        }\n      };\n    } else if (type.equals(Constants.ONPROBE_DESC)) {\n      op = new OnProbe(this);\n      op.setTargetName(name);\n      op.setTargetDescriptor(desc);\n      return new AnnotationVisitor(Opcodes.ASM9, av) {\n        @Override\n        public void visit(String name, Object value) {\n          super.visit(name, value);\n\n          switch (name) {\n            case \"namespace\":\n              op.setNamespace((String) value);\n              break;\n            case \"name\":\n              op.setName((String) value);\n              break;\n          }\n        }\n      };\n    } else if (type.equals(Constants.SAMPLED_DESC)) {\n      if (om != null) {\n        om.setSamplerKind(Sampled.Sampler.Adaptive);\n        return new AnnotationVisitor(Opcodes.ASM9, av) {\n          private boolean meanSet = false;\n\n          @Override\n          public void visit(String name, Object value) {\n            super.visit(name, value);\n\n            if (name.equals(\"mean\")) {\n              om.setSamplerMean((Integer) value);\n              meanSet = true;\n            }\n          }\n\n          @Override\n          public void visitEnum(String name, String desc, String value) {\n            super.visitEnum(name, desc, value);\n\n            if (name.equals(\"kind\") && desc.equals(Constants.SAMPLER_DESC)) {\n              om.setSamplerKind(Sampled.Sampler.valueOf(value));\n            }\n          }\n\n          @Override\n          public void visitEnd() {\n            if (!meanSet) {\n              if (om.getSamplerKind() == Sampled.Sampler.Adaptive) {\n                om.setSamplerMean(500);\n              } else if (om.getSamplerKind() == Sampled.Sampler.Const) {\n                om.setSamplerMean(Sampled.MEAN_DEFAULT);\n              }\n            }\n            if (om.getSamplerKind() == Sampled.Sampler.Adaptive) {\n              // the time frame for adaptive sampling\n              // should be at least 180ns -\n              // (80ns timestamps + 15ns stub) * 2 safety margin\n              if (om.getSamplerMean() < 180) {\n                System.err.println(\n                    \"Setting the adaptive sampler time windows to the default of 180ns\");\n                om.setSamplerMean(180);\n              }\n            }\n            super.visitEnd();\n          }\n        };\n      }\n      sampled = true;\n    }\n    return av;\n  }\n\n  @Override\n  public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {\n    AnnotationVisitor av = super.visitParameterAnnotation(parameter, desc, visible);\n\n    if (om != null) {\n      av = setSpecialParameters(om, desc, parameter, av);\n    } else if (op != null) {\n      av = setSpecialParameters(op, desc, parameter, av);\n    }\n\n    return av;\n  }\n\n  @Override\n  public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {\n    owner = cn.translateOwner(owner);\n    if (opcode == Opcodes.INVOKESTATIC) {\n      graph.addEdge(methodId, CallGraph.methodId(name, desc));\n    }\n    super.visitMethodInsn(opcode, owner, name, desc, itf);\n  }\n\n  @Override\n  public void visitFieldInsn(int opcode, String owner, String name, String desc) {\n    super.visitFieldInsn(opcode, cn.translateOwner(owner), name, desc);\n  }\n\n  public boolean isBcpRequired() {\n    return isBTraceHandler && om == null && op == null;\n  }\n\n  public boolean isBTraceHandler() {\n    return isBTraceHandler;\n  }\n\n  public OnMethod getOnMethod() {\n    return om;\n  }\n\n  public boolean isSampled() {\n    return sampled;\n  }\n\n  public Set<BTraceMethodNode> getCallees() {\n    return cn.callees(name, desc);\n  }\n\n  public Set<BTraceMethodNode> getCallers() {\n    return cn.callers(name, desc);\n  }\n\n  boolean isFieldInjected(String name) {\n    return cn.isFieldInjected(name);\n  }\n\n  boolean isServiceType(String typeName) {\n    return cn.isServiceType(typeName);\n  }\n\n  OnProbe getOnProbe() {\n    return op;\n  }\n\n  private AnnotationVisitor setSpecialParameters(\n      SpecialParameterHolder ph, String desc, int parameter, AnnotationVisitor av) {\n    // for OnProbe the 'loc' variable will be null; we will need to verfiy the placement later on\n    if (desc.equals(Constants.SELF_DESC)) {\n      ph.setSelfParameter(parameter);\n    } else if (desc.equals(Constants.BTRACE_PROBECLASSNAME_DESC)) {\n      ph.setClassNameParameter(parameter);\n    } else if (desc.equals(Constants.BTRACE_PROBEMETHODNAME_DESC)) {\n      ph.setMethodParameter(parameter);\n      av =\n          new AnnotationVisitor(Opcodes.ASM9, av) {\n            @Override\n            public void visit(String name, Object val) {\n              if (name.equals(\"fqn\")) {\n                ph.setMethodFqn((Boolean) val);\n              }\n              super.visit(name, val);\n            }\n          };\n    } else if (desc.equals(Constants.RETURN_DESC)) {\n      ph.setReturnParameter(parameter);\n    } else if (desc.equals(Constants.TARGETMETHOD_DESC)) {\n      ph.setTargetMethodOrFieldParameter(parameter);\n\n      av =\n          new AnnotationVisitor(Opcodes.ASM9, av) {\n            @Override\n            public void visit(String name, Object val) {\n              if (name.equals(\"fqn\")) {\n                ph.setTargetMethodOrFieldFqn((Boolean) val);\n              }\n              super.visit(name, val);\n            }\n          };\n    } else if (desc.equals(Constants.TARGETINSTANCE_DESC)) {\n      ph.setTargetInstanceParameter(parameter);\n    } else if (desc.equals(Constants.DURATION_DESC)) {\n      ph.setDurationParameter(parameter);\n    }\n    return av;\n  }\n\n  private void verifySpecialParameters(OnMethod om) {\n    Location loc = om.getLocation();\n    if (om.getReturnParameter() != -1) {\n      if (!(loc.getValue() == Kind.RETURN\n          || (loc.getValue() == Kind.CALL && loc.getWhere() == Where.AFTER)\n          || (loc.getValue() == Kind.ARRAY_GET && loc.getWhere() == Where.AFTER)\n          || (loc.getValue() == Kind.FIELD_GET && loc.getWhere() == Where.AFTER)\n          || (loc.getValue() == Kind.NEW && loc.getWhere() == Where.AFTER)\n          || (loc.getValue() == Kind.NEWARRAY && loc.getWhere() == Where.AFTER))) {\n        Verifier.reportError(\n            \"return.desc.invalid\",\n            om.getTargetName() + om.getTargetDescriptor() + \"(\" + om.getReturnParameter() + \")\");\n      }\n    }\n    if (om.getTargetMethodOrFieldParameter() != -1) {\n      if (!(loc.getValue() == Kind.CALL\n          || loc.getValue() == Kind.FIELD_GET\n          || loc.getValue() == Kind.FIELD_SET\n          || loc.getValue() == Kind.ARRAY_GET\n          || loc.getValue() == Kind.ARRAY_SET)) {\n        Verifier.reportError(\n            \"target-method.desc.invalid\",\n            om.getTargetName()\n                + om.getTargetDescriptor()\n                + \"(\"\n                + om.getTargetMethodOrFieldParameter()\n                + \")\");\n      }\n    }\n    if (om.getTargetInstanceParameter() != -1) {\n      if (!(loc.getValue() == Kind.CALL\n          || loc.getValue() == Kind.FIELD_GET\n          || loc.getValue() == Kind.FIELD_SET\n          || loc.getValue() == Kind.ARRAY_GET\n          || loc.getValue() == Kind.ARRAY_SET\n          || loc.getValue() == Kind.INSTANCEOF\n          || loc.getValue() == Kind.CHECKCAST\n          || loc.getValue() == Kind.ERROR\n          || loc.getValue() == Kind.THROW\n          || loc.getValue() == Kind.CATCH\n          || loc.getValue() == Kind.SYNC_ENTRY\n          || loc.getValue() == Kind.SYNC_EXIT)) {\n        Verifier.reportError(\n            \"target-instance.desc.invalid\",\n            om.getTargetName()\n                + om.getTargetDescriptor()\n                + \"(\"\n                + om.getTargetInstanceParameter()\n                + \")\");\n      }\n    }\n    if (om.getDurationParameter() != -1) {\n      if (!((loc.getValue() == Kind.RETURN || loc.getValue() == Kind.ERROR)\n          || (loc.getValue() == Kind.CALL && loc.getWhere() == Where.AFTER))) {\n        Verifier.reportError(\n            \"duration.desc.invalid\",\n            om.getTargetName() + om.getTargetDescriptor() + \"(\" + om.getDurationParameter() + \")\");\n      }\n    }\n  }\n\n  @Override\n  public String toString() {\n    return \"BTraceMethodNode{name = \" + name + \", desc=\" + desc + '}';\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceMethodVisitor.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\n\npublic class BTraceMethodVisitor extends MethodVisitor {\n  private final MethodInstrumentorHelper mHelper;\n\n  public BTraceMethodVisitor(MethodVisitor mv, MethodInstrumentorHelper mHelper) {\n    super(Opcodes.ASM9, mv);\n    this.mHelper = mHelper;\n  }\n\n  public final int storeAsNew() {\n    return mHelper.storeAsNew();\n  }\n\n  public final int storeNewLocal(Type t) {\n    int index = mHelper.newVar(t);\n    super.visitVarInsn(t.getOpcode(Opcodes.ISTORE), index);\n    return index;\n  }\n\n  public final void addTryCatchHandler(Label start, Label handler) {\n    mHelper.addTryCatchHandler(start, handler);\n  }\n\n  public void insertFrameReplaceStack(Label l, Type... stack) {\n    mHelper.insertFrameReplaceStack(l, stack);\n  }\n\n  public void insertFrameAppendStack(Label l, Type... stack) {\n    mHelper.insertFrameAppendStack(l, stack);\n  }\n\n  public void insertFrameSameStack(Label l) {\n    mHelper.insertFrameSameStack(l);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbe.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n *\n * Copyright (c) 2017, 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\npackage org.openjdk.btrace.instr;\n\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodType;\nimport java.util.Collection;\nimport java.util.Set;\nimport org.objectweb.asm.ClassVisitor;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.extensions.Permission;\n\npublic interface BTraceProbe {\n  /**\n   * Returns the action method prefix for this probe.\n   * This is computed once and cached.\n   *\n   * Format: BTRACE_METHOD_PREFIX + className.replace('/', '$') + \"$\"\n   * Example: \"$btrace$com$example$MyProbe$\"\n   *\n   * @return cached action prefix\n   */\n  String getActionPrefix();\n\n  Collection<OnMethod> getApplicableHandlers(BTraceClassReader cr);\n\n  byte[] getFullBytecode();\n\n  byte[] getDataHolderBytecode();\n\n  String getClassName();\n\n  String getClassName(boolean internal);\n\n  boolean isClassRenamed();\n\n  boolean isTransforming();\n\n  boolean isVerified();\n\n  void notifyTransform(String className);\n\n  Iterable<OnMethod> onmethods();\n\n  Iterable<OnProbe> onprobes();\n\n  Class<?> register(BTraceRuntime.Impl rt, BTraceTransformer t);\n\n  /**\n   * @return the defined probe {@link Class}, or {@code null} if the probe has not been\n   *         registered (or has been unregistered).\n   */\n  Class<?> getProbeClass();\n\n  void unregister();\n\n  boolean willInstrument(Class<?> clz);\n\n  void checkVerified();\n\n  void copyHandlers(ClassVisitor copyingVisitor);\n\n  void applyArgs(ArgsMap argsMap);\n\n  BTraceRuntime.Impl getRuntime();\n\n  /**\n   * Returns the set of permissions required by this probe.\n   *\n   * @return unmodifiable set of required permissions\n   */\n  Set<Permission> getRequiredPermissions();\n\n  /**\n   * Look up a previously cached {@link MethodHandle} for a handler on this probe.\n   *\n   * <p>The cache is per-probe so it dies naturally when the probe object is collected —\n   * no cross-probe scan required on unregister. Returns {@code null} on miss, or when\n   * the probe implementation has no cache (e.g. stub probes in tests).\n   */\n  default MethodHandle getCachedHandler(String handlerName, MethodType type) {\n    return null;\n  }\n\n  /**\n   * Store a resolved handler {@link MethodHandle} for subsequent lookups. Implementations\n   * without a backing cache (e.g. stub probes in tests) may silently drop the entry.\n   */\n  default void cacheHandler(String handlerName, MethodType type, MethodHandle mh) {\n    // no-op by default\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbeFactory.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n *\n * Copyright (c) 2017, 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\npackage org.openjdk.btrace.instr;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.DataInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A factory class for {@link BTraceProbeNode} instances\n *\n * @author Jaroslav Bachorik\n */\npublic final class BTraceProbeFactory {\n  private static final Logger log = LoggerFactory.getLogger(BTraceProbeFactory.class);\n\n  private static final int CLASS_MAGIC = 0xCAFEBABE;\n\n  private final SharedSettings settings;\n\n  public BTraceProbeFactory(SharedSettings settings) {\n    this.settings = settings;\n  }\n\n  private static void applyArgs(BTraceProbe bp, ArgsMap argsMap) {\n    if (bp != null && argsMap != null && !argsMap.isEmpty()) {\n      bp.applyArgs(argsMap);\n    }\n  }\n\n  /**\n   * Check if a particular file can be loaded as a BTrace probe. Currently only the plain class file\n   * and BTrace probe pack are supported.\n   *\n   * @param filePath the file path\n   * @return {@literal true} if a BTrace probe can be reconstructed from data in the given file\n   */\n  public static boolean canLoad(String filePath) {\n    return canLoad(filePath, null);\n  }\n\n  public static boolean canLoad(String filePath, ClassLoader cl) {\n    if (filePath == null) {\n      return false;\n    }\n    Path path = Paths.get(filePath);\n    InputStream is = null;\n    try {\n      if (!Files.exists(path)) {\n        // try to load from the classpath\n        if (cl == null) {\n          cl = ClassLoader.getSystemClassLoader();\n        }\n        is = cl.getResourceAsStream(\"META-INF/btrace/\" + filePath);\n      } else {\n        is = Files.newInputStream(path);\n      }\n      if (is != null) {\n        try {\n          try (DataInputStream dis = new DataInputStream(is)) {\n            int magic = dis.readInt();\n            return magic == CLASS_MAGIC || magic == BTraceProbePersisted.MAGIC;\n          }\n        } catch (IOException ignored) {\n          is = null;\n        }\n      }\n    } catch (IOException ignored) {\n    } finally {\n      if (is != null) {\n        try {\n          is.close();\n        } catch (IOException ignored) {\n        }\n      }\n    }\n    return false;\n  }\n\n  SharedSettings getSettings() {\n    return settings;\n  }\n\n  public BTraceProbe createProbe(byte[] code) {\n    return createProbe(code, null);\n  }\n\n  public BTraceProbe createProbe(byte[] code, ArgsMap argsMap) {\n    BTraceProbe bp = null;\n\n    int mgc =\n        ((code[0] & 0xff) << 24)\n            | ((code[1] & 0xff) << 16)\n            | ((code[2] & 0xff) << 8)\n            | ((code[3] & 0xff));\n    if (mgc == BTraceProbePersisted.MAGIC) {\n      BTraceProbePersisted bpp = new BTraceProbePersisted(this);\n      try (DataInputStream dis =\n          new DataInputStream(new ByteArrayInputStream(Arrays.copyOfRange(code, 4, code.length)))) {\n        bpp.read(dis);\n        bp = bpp;\n      } catch (IOException e) {\n        log.debug(\"Failed to read BTrace pack\", e);\n      }\n    } else {\n      bp = new BTraceProbeNode(this, code);\n    }\n\n    applyArgs(bp, argsMap);\n    return bp;\n  }\n\n  public BTraceProbe createProbe(InputStream code) {\n    return createProbe(code, null);\n  }\n\n  public BTraceProbe createProbe(InputStream code, ArgsMap argsMap) {\n    BTraceProbe bp = null;\n    try (DataInputStream dis = new DataInputStream(code)) {\n      dis.mark(0);\n      int mgc = dis.readInt();\n      if (mgc == BTraceProbePersisted.MAGIC) {\n        BTraceProbePersisted bpp = new BTraceProbePersisted(this);\n        bpp.read(dis);\n        bp = bpp;\n      } else {\n        code.reset();\n        bp = new BTraceProbeNode(this, code);\n      }\n    } catch (IOException e) {\n      log.debug(\"Failed to create a probe\", e);\n    }\n\n    applyArgs(bp, argsMap);\n    return bp;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbeNode.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.AnnotationVisitor;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.ClassWriter;\nimport org.objectweb.asm.FieldVisitor;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\nimport org.objectweb.asm.tree.ClassNode;\nimport org.objectweb.asm.tree.MethodNode;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.DebugSupport;\nimport org.openjdk.btrace.core.Messages;\nimport org.openjdk.btrace.core.VerifierException;\nimport org.openjdk.btrace.core.comm.RetransformClassNotification;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.extension.ServiceDeclarationRegistry;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic final class BTraceProbeNode extends ClassNode implements BTraceProbe {\n  private static final Logger log = LoggerFactory.getLogger(BTraceProbeNode.class);\n\n  final BTraceProbeSupport delegate;\n\n  final BTraceProbeFactory factory;\n\n  final DebugSupport debug;\n\n  private final CallGraph graph;\n\n  private final Map<String, BTraceMethodNode> idmap;\n  private final Set<String> jfrHandlers = new HashSet<>();\n  private final Preprocessor prep;\n  private final BTraceBCPClassLoader bcpResourceClassLoader;\n\n  private volatile BTraceRuntime.Impl rt = null;\n\n  private BTraceTransformer transformer;\n  private VerifierException verifierException = null;\n\n  private BTraceProbeNode(BTraceProbeFactory factory) {\n    super(Opcodes.ASM9);\n    this.factory = factory;\n    bcpResourceClassLoader = new BTraceBCPClassLoader(factory.getSettings());\n    debug = new DebugSupport(factory.getSettings());\n    delegate = new BTraceProbeSupport();\n    idmap = new HashMap<>();\n    graph = new CallGraph();\n    prep = new Preprocessor();\n  }\n\n  BTraceProbeNode(BTraceProbeFactory factory, byte[] code) {\n    this(factory);\n    initialize(code);\n  }\n\n  BTraceProbeNode(BTraceProbeFactory factory, InputStream code) throws IOException {\n    this(factory);\n    initialize(code);\n  }\n\n  @Override\n  public boolean isTransforming() {\n    return delegate.isTransforming();\n  }\n\n  @Override\n  public void visit(\n      int version, int access, String name, String sig, String superType, String[] itfcs) {\n    delegate.setClassName(name);\n    super.visit(version, access, delegate.getClassName(true), sig, superType, itfcs);\n  }\n\n  @Override\n  public MethodVisitor visitMethod(\n      int access, String name, String desc, String sig, String[] exceptions) {\n    super.visitMethod(access, name, desc, sig, exceptions);\n    MethodNode mn = methods.remove(methods.size() - 1);\n    BTraceMethodNode bmn = new BTraceMethodNode(mn, this, jfrHandlers.contains(name));\n    methods.add(bmn);\n    idmap.put(CallGraph.methodId(name, desc), bmn);\n    return isTrusted()\n        ? bmn\n        : new MethodVerifier(\n            bmn, access, delegate.getOrigName(), name, desc, bcpResourceClassLoader);\n  }\n\n  @Override\n  public FieldVisitor visitField(\n      int access, String name, String desc, String signature, Object value) {\n    return new FieldVisitor(Opcodes.ASM9, super.visitField(access, name, desc, signature, value)) {\n      @Override\n      public AnnotationVisitor visitAnnotation(String type, boolean aVisible) {\n        AnnotationVisitor av = super.visitAnnotation(type, aVisible);\n        if (type.equals(Constants.INJECTED_DESC)) {\n          // Bytecode-time validation for @Injected fields:\n          // This ASM-based check enforces that the injected service type is declared by\n          // some available extension (as exposed via ServiceDeclarationRegistry). It does\n          // not load classes; instead, the agent registers a resolver that knows about\n          // extension manifests. This complements the runtime validation in\n          // org.openjdk.btrace.agent.Client#validateDeclaredServices, which uses reflection\n          // to account for classloader identity, JPMS access, and linkage in the actual\n          // target JVM.\n          String internal = Type.getType(desc).getInternalName();\n          String fqcn = internal.replace('/', '.');\n          if (!ServiceDeclarationRegistry.isDeclaredService(fqcn)) {\n            throw new VerifierException(Messages.get(\"invalid.injected.service\") + \": \" + fqcn);\n          }\n          delegate.addServiceField(name, internal);\n        }\n        if (type.equals(\"Lorg/openjdk/btrace/core/annotations/Event;\")) {\n          av =\n              new AnnotationVisitor(Opcodes.ASM8, av) {\n                @Override\n                public void visit(String name, Object value) {\n                  if (name.equals(\"handler\") && value instanceof String) {\n                    jfrHandlers.add((String) value);\n                  }\n                  super.visit(name, value);\n                }\n              };\n        }\n        return av;\n      }\n    };\n  }\n\n  @Override\n  public Collection<OnMethod> getApplicableHandlers(BTraceClassReader cr) {\n    return delegate.getApplicableHandlers(cr);\n  }\n\n  @Override\n  public Iterable<OnMethod> onmethods() {\n    return delegate.onmethods();\n  }\n\n  public Collection<OnMethod> getOnMethods() {\n    return delegate.getOnMethods();\n  }\n\n  @Override\n  public Iterable<OnProbe> onprobes() {\n    return delegate.onprobes();\n  }\n\n  @Override\n  public String getClassName() {\n    return getClassName(false);\n  }\n\n  @Override\n  public String getClassName(boolean internal) {\n    return delegate.getClassName(internal);\n  }\n\n  String translateOwner(String owner) {\n    return delegate.translateOwner(owner);\n  }\n\n  @Override\n  public Class<?> register(BTraceRuntime.Impl rt, BTraceTransformer t) {\n    byte[] code = getBytecode(true);\n    if (debug.isDumpClasses()) {\n      debug.dumpClass(name + \"_bcp\", code);\n    }\n    Class<?> clz = delegate.defineClass(rt, code);\n    HandlerRepositoryImpl.registerProbe(this);\n    t.register(this);\n    transformer = t;\n    this.rt = rt;\n    return clz;\n  }\n\n  @Override\n  public Class<?> getProbeClass() {\n    return delegate.getProbeClass();\n  }\n\n  @Override\n  public java.lang.invoke.MethodHandle getCachedHandler(\n      String handlerName, java.lang.invoke.MethodType type) {\n    return delegate.getCachedHandler(handlerName, type);\n  }\n\n  @Override\n  public void cacheHandler(\n      String handlerName, java.lang.invoke.MethodType type, java.lang.invoke.MethodHandle mh) {\n    delegate.cacheHandler(handlerName, type, mh);\n  }\n\n  @Override\n  public void unregister() {\n    HandlerRepositoryImpl.unregisterProbe(this);\n    if (transformer != null && isTransforming()) {\n      if (log.isDebugEnabled()) {\n        log.debug(\"onExit: removing transformer for {}\", getClassName());\n      }\n      transformer.unregister(this);\n    }\n    delegate.clearProbeClass();\n    rt = null;\n  }\n\n  @Override\n  public byte[] getFullBytecode() {\n    return getBytecode(false);\n  }\n\n  @Override\n  public byte[] getDataHolderBytecode() {\n    return getBytecode(true);\n  }\n\n  @Override\n  public BTraceRuntime.Impl getRuntime() {\n    return rt;\n  }\n\n  private byte[] getBytecode(boolean onlyBcpMethods) {\n    ClassWriter cw = InstrumentUtils.newClassWriter(true);\n    ClassVisitor cv = cw;\n    if (onlyBcpMethods) {\n      cv =\n          new ClassVisitor(Opcodes.ASM9, cw) {\n            @Override\n            public MethodVisitor visitMethod(\n                int access, String name, String desc, String sig, String[] exceptions) {\n              if (name.startsWith(\"<\")) {\n                // never check constructor and static initializer\n                return super.visitMethod(access, name, desc, sig, exceptions);\n              }\n              BTraceMethodNode bmn = idmap.get(CallGraph.methodId(name, desc));\n              if (bmn != null) {\n                // Include BCP-required methods AND probe handler methods:\n                // Handlers are invoked via INVOKEDYNAMIC (IndyDispatcher.bootstrap),\n                // so the handler method body must be present in the bootstrap-CL probe class.\n                // This applies to @OnMethod handlers (om != null) and @OnProbe handlers\n                // (op != null — mapped to @OnMethod entries via mapOnProbes()).\n                boolean isHandler = bmn.getOnMethod() != null || bmn.getOnProbe() != null;\n                if (bmn.isBcpRequired() || isHandler) {\n                  // Handlers: rewrite descriptor AnyType → Object to match the INDY call site\n                  // type (Instrumentor.invokeBTraceAction replaces AnyType with Object in\n                  // the INDY descriptor for JVM stack compatibility).\n                  String effectiveDesc =\n                      isHandler\n                          ? desc.replace(Constants.ANYTYPE_DESC, Constants.OBJECT_DESC)\n                          : desc;\n                  return super.visitMethod(access, name, effectiveDesc, sig, exceptions);\n                }\n                for (BTraceMethodNode c : bmn.getCallers()) {\n                  boolean callerIsHandler = c.getOnMethod() != null || c.getOnProbe() != null;\n                  if (c.isBcpRequired() || callerIsHandler) {\n                    return super.visitMethod(access, name, desc, sig, exceptions);\n                  }\n                }\n                return null;\n              }\n              return super.visitMethod(access, name, desc, sig, exceptions);\n            }\n          };\n    }\n    accept(cv);\n    return cw.toByteArray();\n  }\n\n  /**\n   * Collects all the methods reachable from this particular method\n   *\n   * @param name the method name\n   * @param desc the method descriptor\n   * @return the callee reachability closure\n   */\n  Set<BTraceMethodNode> callees(String name, String desc) {\n    Set<String> closure = new HashSet<>();\n    graph.callees(name, desc, closure);\n    return fromIdSet(closure);\n  }\n\n  /**\n   * Collects all the methods from which this particular method is reachable\n   *\n   * @param name the method name\n   * @param desc the method descriptor\n   * @return the caller reachability closure\n   */\n  Set<BTraceMethodNode> callers(String name, String desc) {\n    Set<String> closure = new HashSet<>();\n    graph.callers(name, desc, closure);\n    return fromIdSet(closure);\n  }\n\n  @Override\n  public boolean willInstrument(Class<?> clz) {\n    return delegate.willInstrument(clz);\n  }\n\n  @Override\n  public boolean isClassRenamed() {\n    return delegate.isClassRenamed();\n  }\n\n  @Override\n  public boolean isVerified() {\n    return verifierException == null;\n  }\n\n  @Override\n  public String getActionPrefix() {\n    return delegate.getActionPrefix();\n  }\n\n  private VerifierException getVerifierException() {\n    return verifierException;\n  }\n\n  boolean isFieldInjected(String name) {\n    return delegate.isFieldInjected(name);\n  }\n\n  boolean isServiceType(String typeName) {\n    return delegate.isServiceType(typeName);\n  }\n\n  void addOnMethod(OnMethod om) {\n    delegate.addOnMethod(om);\n  }\n\n  void addOnProbe(OnProbe op) {\n    delegate.addOnProbe(op);\n  }\n\n  void addRequiredPermission(Permission permission) {\n    delegate.addRequiredPermission(permission);\n  }\n\n  @Override\n  public Set<Permission> getRequiredPermissions() {\n    return delegate.getRequiredPermissions();\n  }\n\n  void setTrusted() {\n    delegate.setTrusted();\n  }\n\n  boolean isTrusted() {\n    return delegate.isTrusted();\n  }\n\n  CallGraph getGraph() {\n    return graph;\n  }\n\n  @Override\n  public void notifyTransform(String className) {\n    if (rt != null && factory.getSettings().isTrackRetransforms()) {\n      rt.sendCommand(new RetransformClassNotification(className.replace('/', '.')));\n    }\n  }\n\n  @Override\n  public void checkVerified() {\n    if (!isVerified()) {\n      throw getVerifierException();\n    }\n  }\n\n  @Override\n  public void copyHandlers(ClassVisitor copyingVisitor) {\n    Set<MethodNode> copyNodes = new TreeSet<>(BTraceMethodNode.COMPARATOR);\n\n    for (OnMethod om : onmethods()) {\n      if (!om.isCalled()) {\n        continue;\n      }\n\n      BTraceMethodNode bmn = om.getMethodNode();\n\n      MethodNode mn = copy(bmn);\n\n      copyNodes.add(mn);\n      for (BTraceMethodNode c : bmn.getCallees()) {\n        copyNodes.add(copy(c));\n      }\n    }\n    copyingVisitor.visit(\n        Opcodes.V1_7,\n        Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL,\n        getClassName(true),\n        null,\n        \"java/lang/Object\",\n        null);\n    for (MethodNode mn : copyNodes) {\n      mn.accept(copyingVisitor);\n    }\n    copyingVisitor.visitEnd();\n  }\n\n  @Override\n  public void applyArgs(ArgsMap argsMap) {\n    delegate.applyArgs(argsMap);\n  }\n\n  /** Maps a list of @OnProbe's to a list @OnMethod's using probe descriptor XML files. */\n  private void mapOnProbes() {\n    ProbeDescriptorLoader pdl = getProbeDescriptorLoader();\n\n    for (OnProbe op : delegate.onprobes()) {\n      String ns = op.getNamespace();\n      if (log.isDebugEnabled()) {\n        log.debug(\"about to load probe descriptor for namespace {}\", ns);\n      }\n      // load probe descriptor for this namespace\n      ProbeDescriptor probeDesc = pdl.load(ns);\n      if (probeDesc == null) {\n        if (log.isDebugEnabled()) {\n          log.debug(\"failed to find probe descriptor for namespace {}\", ns);\n        }\n        continue;\n      }\n      // find particular probe mappings using \"local\" name\n      OnProbe foundProbe = probeDesc.findProbe(op.getName());\n      if (foundProbe == null) {\n        if (log.isDebugEnabled()) {\n          log.debug(\"no probe mappings for {}\", op.getName());\n        }\n        continue;\n      }\n      if (log.isDebugEnabled()) {\n        log.debug(\"found probe mappings for {}\", op.getName());\n      }\n      Collection<OnMethod> omColl = foundProbe.getOnMethods();\n      for (OnMethod om : omColl) {\n        // copy the info in a new OnMethod so that\n        // we can set target method name and descriptor\n        // Note that the probe descriptor cache is used\n        // across BTrace sessions. So, we should not update\n        // cached OnProbes (and their OnMethods).\n        OnMethod omn = new OnMethod(op.getMethodNode());\n        omn.copyFrom(om);\n        omn.setTargetName(op.getTargetName());\n        omn.setTargetDescriptor(op.getTargetDescriptor());\n        omn.setClassNameParameter(op.getClassNameParameter());\n        omn.setMethodParameter(op.getMethodParameter());\n        omn.setDurationParameter(op.getDurationParameter());\n        omn.setMethodFqn(op.isMethodFqn());\n        omn.setReturnParameter(op.getReturnParameter());\n        omn.setSelfParameter(op.getSelfParameter());\n        omn.setTargetInstanceParameter(op.getTargetInstanceParameter());\n        omn.setTargetMethodOrFieldFqn(op.isTargetMethodOrFieldFqn());\n        omn.setTargetMethodOrFieldParameter(op.getTargetMethodOrFieldParameter());\n        addOnMethod(omn);\n      }\n    }\n  }\n\n  private ProbeDescriptorLoader getProbeDescriptorLoader() {\n    String path = factory.getSettings().getProbeDescPath();\n    return new ProbeDescriptorLoader(path);\n  }\n\n  private void initialize(byte[] code) {\n    ClassReader cr = new ClassReader(code);\n    if (debug.isDumpClasses()) {\n      debug.dumpClass(cr.getClassName() + \"_orig\", code);\n    }\n    initialize(cr);\n  }\n\n  private void initialize(InputStream code) throws IOException {\n    initialize(readFully(code));\n  }\n\n  private void initialize(ClassReader cr) {\n    try {\n      Verifier v = new Verifier(this, factory.getSettings().isTrusted());\n      log.debug(\"verifying BTrace class ...\");\n      cr.accept(v, ClassReader.SKIP_DEBUG);\n      if (log.isDebugEnabled()) {\n        String clzName = getClassName();\n        log.debug(\"BTrace class {} verified\", clzName);\n        log.debug(\"preprocessing BTrace class {} ...\", clzName);\n      }\n      prep.process(this);\n      log.debug(\"... preprocessed\");\n      try {\n        Class.forName(\"javax.xml.bind.JAXBException\");\n        mapOnProbes();\n      } catch (ClassNotFoundException e) {\n        log.debug(\"XML bindings are missing. @OnProbe support is disabled.\");\n      }\n    } catch (VerifierException e) {\n      verifierException = e;\n    } finally {\n      if (debug.isDumpClasses() && name != null) {\n        debug.dumpClass(name, getBytecode(false));\n      }\n    }\n  }\n\n  private Set<BTraceMethodNode> fromIdSet(Set<String> ids) {\n    Set<BTraceMethodNode> methods = new HashSet<>();\n    for (String id : ids) {\n      BTraceMethodNode mn = idmap.get(id);\n      if (mn != null) {\n        methods.add(mn);\n      }\n    }\n    return methods;\n  }\n\n  private MethodNode copy(MethodNode n) {\n    String[] exceptions = n.exceptions != null ? n.exceptions.toArray(new String[0]) : null;\n    MethodNode mn = new MethodNode(Opcodes.ASM9, n.access, n.name, n.desc, n.signature, exceptions);\n    n.accept(mn);\n    mn.access = Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE;\n    mn.desc = mn.desc.replace(Constants.ANYTYPE_DESC, Constants.OBJECT_DESC);\n    mn.signature =\n        mn.signature != null\n            ? mn.signature.replace(Constants.ANYTYPE_DESC, Constants.OBJECT_DESC)\n            : null;\n    mn.name = getActionPrefix() + mn.name;\n    return mn;\n  }\n\n  private byte[] readFully(InputStream is) throws IOException {\n    int bufSize = 512;\n    int pos = 0;\n    byte[] finArr = new byte[1024];\n    byte[] buff = new byte[bufSize];\n\n    int read = 0;\n    while ((read = is.read(buff, 0, bufSize)) > 0) {\n      int newpos = pos + read;\n      if (newpos >= finArr.length) {\n        finArr = Arrays.copyOf(finArr, finArr.length * 2);\n      }\n      System.arraycopy(buff, 0, finArr, pos, read);\n      pos = newpos;\n    }\n    return Arrays.copyOfRange(finArr, 0, pos);\n  }\n\n  @Override\n  public String toString() {\n    return \"BTraceProbe{\" + \"delegate=\" + delegate + '}';\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbePersisted.java",
    "content": "/*\n * Copyright (c) 2017, 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\npackage org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.FieldVisitor;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.DebugSupport;\nimport org.openjdk.btrace.core.VerifierException;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.core.comm.RetransformClassNotification;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.objectweb.asm.Opcodes.AASTORE;\nimport static org.objectweb.asm.Opcodes.ACC_ENUM;\nimport static org.objectweb.asm.Opcodes.ACC_INTERFACE;\nimport static org.objectweb.asm.Opcodes.ACC_PRIVATE;\nimport static org.objectweb.asm.Opcodes.ACC_PUBLIC;\nimport static org.objectweb.asm.Opcodes.ACC_STATIC;\nimport static org.objectweb.asm.Opcodes.ACC_SYNCHRONIZED;\nimport static org.objectweb.asm.Opcodes.ANEWARRAY;\nimport static org.objectweb.asm.Opcodes.ASM9;\nimport static org.objectweb.asm.Opcodes.ATHROW;\nimport static org.objectweb.asm.Opcodes.BASTORE;\nimport static org.objectweb.asm.Opcodes.CASTORE;\nimport static org.objectweb.asm.Opcodes.DASTORE;\nimport static org.objectweb.asm.Opcodes.FASTORE;\nimport static org.objectweb.asm.Opcodes.IASTORE;\nimport static org.objectweb.asm.Opcodes.INVOKEINTERFACE;\nimport static org.objectweb.asm.Opcodes.INVOKESPECIAL;\nimport static org.objectweb.asm.Opcodes.INVOKESTATIC;\nimport static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;\nimport static org.objectweb.asm.Opcodes.LASTORE;\nimport static org.objectweb.asm.Opcodes.MONITORENTER;\nimport static org.objectweb.asm.Opcodes.MONITOREXIT;\nimport static org.objectweb.asm.Opcodes.NEW;\nimport static org.objectweb.asm.Opcodes.NEWARRAY;\nimport static org.objectweb.asm.Opcodes.PUTFIELD;\nimport static org.objectweb.asm.Opcodes.PUTSTATIC;\nimport static org.objectweb.asm.Opcodes.RET;\nimport static org.objectweb.asm.Opcodes.SASTORE;\n\npublic class BTraceProbePersisted implements BTraceProbe {\n  private static final Logger log = LoggerFactory.getLogger(BTraceProbePersisted.class);\n\n  static final int MAGIC = 0xbacecaca;\n\n  private static final int VERSION = 3;\n\n  final BTraceProbeSupport delegate;\n  private final BTraceProbeFactory factory;\n  private final DebugSupport debug;\n  private final AtomicBoolean triedVerify = new AtomicBoolean(false);\n  private final Map<String, Set<String>> calleeMap = new HashMap<>();\n  private volatile BTraceRuntime.Impl rt = null;\n  private BTraceTransformer transformer;\n  private byte[] fullData = null;\n  private byte[] dataHolder = null;\n  private boolean preverified;\n\n  BTraceProbePersisted(BTraceProbeFactory f) {\n    this(f, null);\n  }\n\n  private BTraceProbePersisted(BTraceProbeFactory f, BTraceProbeSupport delegate) {\n    this.debug = new DebugSupport(f.getSettings());\n    this.delegate = delegate != null ? delegate : new BTraceProbeSupport();\n    factory = f;\n    preverified = false;\n  }\n\n  private BTraceProbePersisted(BTraceProbeNode bpn) {\n    this(bpn.factory, bpn.delegate);\n    fullData = bpn.getFullBytecode();\n    dataHolder = bpn.getDataHolderBytecode();\n    loadCalleeMap(bpn, calleeMap);\n    preverified = true;\n  }\n\n  public static BTraceProbePersisted from(BTraceProbe bp) {\n    return bp instanceof BTraceProbePersisted\n        ? (BTraceProbePersisted) bp\n        : new BTraceProbePersisted((BTraceProbeNode) bp);\n  }\n\n  private static void loadCalleeMap(BTraceProbeNode bpn, Map<String, Set<String>> cMap) {\n    Set<Handler> roots = new HashSet<>();\n    for (OnMethod om : bpn.onmethods()) {\n      roots.add(new Handler(om.getTargetName(), om.getTargetDescriptor()));\n    }\n    for (OnProbe op : bpn.onprobes()) {\n      roots.add(new Handler(op.getTargetName(), op.getTargetDescriptor()));\n    }\n    for (Handler h : roots) {\n      String rootKey = CallGraph.methodId(h.name, h.desc);\n      Set<String> cs = cMap.computeIfAbsent(rootKey, k -> new HashSet<>());\n      for (BTraceMethodNode bmn : bpn.callees(h.name, h.desc)) {\n        cs.add(CallGraph.methodId(bmn.name, bmn.desc));\n      }\n    }\n  }\n\n  private static String getClazz(OnMethod om) {\n    String clzName = om.getClazz();\n\n    if (om.isSubtypeMatcher()) {\n      return \"+\" + om.getClazz();\n    } else {\n      if (om.isClassRegexMatcher()) {\n        clzName = \"/\" + clzName + \"/\";\n      }\n      if (om.isClassAnnotationMatcher()) {\n        clzName = \"@\" + clzName;\n      }\n    }\n\n    return clzName;\n  }\n\n  private static String getMethod(OnMethod om) {\n    String mName = om.getMethod();\n\n    if (om.isMethodRegexMatcher()) {\n      mName = \"/\" + mName + \"/\";\n    }\n\n    if (om.isMethodAnnotationMatcher()) {\n      mName = \"@\" + mName;\n    }\n\n    return mName;\n  }\n\n  public void read(DataInputStream dis) throws IOException {\n    int version = dis.readInt();\n    switch (version) {\n      case 1:\n        {\n          read_1(dis);\n          break;\n        }\n      case 2:\n        {\n          read_2(dis);\n          break;\n        }\n      case 3:\n        {\n          read_3(dis);\n          break;\n        }\n      default:\n        {\n          throw new IOException(\"Unsupported version for persisted probe: \" + version);\n        }\n    }\n  }\n\n  /**\n   * Read in the structure for version 1\n   *\n   * @param dis data input stream\n   * @throws IOException\n   */\n  private void read_1(DataInputStream dis) throws IOException {\n    delegate.setClassName(dis.readUTF());\n    readServices(dis);\n    readOnMethods(dis);\n    readOnProbes(dis);\n    readCallees(dis);\n    readDataHolderClass(dis);\n    readFullData(dis);\n    upgradeBytecode();\n  }\n\n  /**\n   * Read in the structure for version 2\n   *\n   * @param dis data input stream\n   * @throws IOException\n   */\n  private void read_2(DataInputStream dis) throws IOException {\n    delegate.setClassName(dis.readUTF());\n    readServices(dis);\n    readOnMethods(dis);\n    readOnProbes(dis);\n    readCallees(dis);\n    readDataHolderClass(dis);\n    readFullData(dis);\n  }\n\n  /**\n   * Read in the structure for version 3\n   *\n   * @param dis data input stream\n   * @throws IOException\n   */\n  private void read_3(DataInputStream dis) throws IOException {\n    delegate.setClassName(dis.readUTF());\n    readServices(dis);\n    readOnMethods(dis);\n    readOnProbes(dis);\n    readCallees(dis);\n    readPermissions(dis);\n    readDataHolderClass(dis);\n    readFullData(dis);\n  }\n\n  public void write(DataOutputStream dos) {\n    try {\n      dos.writeInt(MAGIC);\n      dos.writeInt(VERSION);\n      dos.writeUTF(getClassName(true));\n      writeServices(dos);\n      writeOnMethods(dos);\n      writeOnProbes(dos);\n      writeCallees(dos);\n      writePermissions(dos);\n      writeDataHolderClass(dos);\n      writeFullData(dos);\n    } catch (IOException e) {\n      log.debug(\"Failed to write probe {}\", getClassName(), e);\n    }\n  }\n\n  private void readServices(DataInputStream dis) throws IOException {\n    int num = dis.readInt();\n    for (int i = 0; i < num; i++) {\n      delegate.addServiceField(dis.readUTF(), dis.readUTF());\n    }\n  }\n\n  private void readOnMethods(DataInputStream dis) throws IOException {\n    int num = dis.readInt();\n    for (int i = 0; i < num; i++) {\n      OnMethod om = new OnMethod();\n      om.setClazz(dis.readUTF());\n      om.setMethod(dis.readUTF());\n      om.setExactTypeMatch(dis.readBoolean());\n      om.setTargetDescriptor(dis.readUTF());\n      om.setTargetName(dis.readUTF());\n      om.setType(dis.readUTF());\n      om.setClassNameParameter(dis.readInt());\n      om.setDurationParameter(dis.readInt());\n      om.setMethodParameter(dis.readInt());\n      om.setReturnParameter(dis.readInt());\n      om.setSelfParameter(dis.readInt());\n      om.setTargetInstanceParameter(dis.readInt());\n      om.setTargetMethodOrFieldParameter(dis.readInt());\n      om.setMethodFqn(dis.readBoolean());\n      om.setTargetMethodOrFieldFqn(dis.readBoolean());\n      om.setSamplerKind(Sampled.Sampler.valueOf(dis.readUTF()));\n      om.setSamplerMean(dis.readInt());\n      om.setLevel(dis.readBoolean() ? Level.fromString(dis.readUTF()) : null);\n      Location loc = new Location();\n      loc.setValue(Kind.valueOf(dis.readUTF()));\n      loc.setWhere(Where.valueOf(dis.readUTF()));\n      loc.setClazz(dis.readBoolean() ? dis.readUTF() : null);\n      loc.setField(dis.readBoolean() ? dis.readUTF() : null);\n      loc.setMethod(dis.readBoolean() ? dis.readUTF() : null);\n      loc.setType(dis.readBoolean() ? dis.readUTF() : null);\n      loc.setLine(dis.readInt());\n      om.setLocation(loc);\n      delegate.addOnMethod(om);\n    }\n  }\n\n  private void readOnProbes(DataInputStream dis) throws IOException {\n    int num = dis.readInt();\n    for (int i = 0; i < num; i++) {\n      OnProbe op = new OnProbe();\n      op.setNamespace(dis.readUTF());\n      op.setName(dis.readUTF());\n      op.setTargetDescriptor(dis.readUTF());\n      op.setTargetName(dis.readUTF());\n      op.setClassNameParameter(dis.readInt());\n      op.setDurationParameter(dis.readInt());\n      op.setMethodParameter(dis.readInt());\n      op.setReturnParameter(dis.readInt());\n      op.setSelfParameter(dis.readInt());\n      op.setTargetInstanceParameter(dis.readInt());\n      op.setTargetMethodOrFieldParameter(dis.readInt());\n      op.setMethodFqn(dis.readBoolean());\n      op.setTargetMethodOrFieldFqn(dis.readBoolean());\n      delegate.addOnProbe(op);\n    }\n  }\n\n  private void readFullData(DataInputStream dis) throws IOException {\n    int fullDataLen = dis.readInt();\n    fullData = new byte[fullDataLen];\n    dis.readFully(fullData);\n    if (fullData.length > 0 && isClassRenamed()) {\n      fullData = ProbeRenameVisitor.rename(getClassName(), fullData);\n    }\n  }\n\n  private void readDataHolderClass(DataInputStream dis) throws IOException {\n    int holderLen = dis.readInt();\n    dataHolder = new byte[holderLen];\n    dis.readFully(dataHolder);\n    if (dataHolder.length > 0 && isClassRenamed()) {\n      dataHolder = ProbeRenameVisitor.rename(getClassName(), dataHolder);\n    }\n  }\n\n  private void readCallees(DataInputStream dis) throws IOException {\n    int cnt = dis.readInt();\n    for (int i = 0; i < cnt; i++) {\n      String from = dis.readUTF();\n      Set<String> calleeSet = calleeMap.computeIfAbsent(from, k -> new HashSet<>());\n      int callees = dis.readInt();\n      for (int j = 0; j < callees; j++) {\n        String to = dis.readUTF();\n        calleeSet.add(to);\n      }\n    }\n  }\n\n  private void readPermissions(DataInputStream dis) throws IOException {\n    int cnt = dis.readInt();\n    for (int i = 0; i < cnt; i++) {\n      String permName = dis.readUTF();\n      try {\n        delegate.addRequiredPermission(Permission.valueOf(permName));\n      } catch (IllegalArgumentException e) {\n        log.warn(\"Unknown permission in probe: {}\", permName);\n      }\n    }\n  }\n\n  private void writeServices(DataOutputStream dos) throws IOException {\n    Map<String, String> svcFields = delegate.serviceFields();\n    dos.writeInt(svcFields.size());\n    for (Map.Entry<String, String> e : svcFields.entrySet()) {\n      dos.writeUTF(e.getKey());\n      dos.writeUTF(e.getValue());\n    }\n  }\n\n  private void writeOnMethods(DataOutputStream dos) throws IOException {\n    Collection<OnMethod> onMethods = delegate.getOnMethods();\n    int cnt = onMethods.size();\n    dos.writeInt(cnt);\n    for (OnMethod om : onMethods) {\n      dos.writeUTF(getClazz(om));\n      dos.writeUTF(getMethod(om));\n      dos.writeBoolean(om.isExactTypeMatch());\n      dos.writeUTF(om.getTargetDescriptor());\n      dos.writeUTF(om.getTargetName());\n      dos.writeUTF(om.getType());\n      dos.writeInt(om.getClassNameParameter());\n      dos.writeInt(om.getDurationParameter());\n      dos.writeInt(om.getMethodParameter());\n      dos.writeInt(om.getReturnParameter());\n      dos.writeInt(om.getSelfParameter());\n      dos.writeInt(om.getTargetInstanceParameter());\n      dos.writeInt(om.getTargetMethodOrFieldParameter());\n      dos.writeBoolean(om.isMethodFqn());\n      dos.writeBoolean(om.isTargetMethodOrFieldFqn());\n      dos.writeUTF(om.getSamplerKind().name());\n      dos.writeInt(om.getSamplerMean());\n      dos.writeBoolean(om.getLevel() != null);\n      if (om.getLevel() != null) {\n        dos.writeUTF(om.getLevel().getValue().toString());\n      }\n      Location loc = om.getLocation();\n      dos.writeUTF(loc.getValue().name());\n      dos.writeUTF(loc.getWhere().name());\n      dos.writeBoolean(loc.getClazz() != null);\n      if (loc.getClazz() != null) {\n        dos.writeUTF(loc.getClazz());\n      }\n      dos.writeBoolean(loc.getField() != null);\n      if (loc.getField() != null) {\n        dos.writeUTF(loc.getField());\n      }\n      dos.writeBoolean(loc.getMethod() != null);\n      if (loc.getMethod() != null) {\n        dos.writeUTF(loc.getMethod());\n      }\n      dos.writeBoolean(loc.getType() != null);\n      if (loc.getType() != null) {\n        dos.writeUTF(loc.getType());\n      }\n      dos.writeInt(loc.getLine());\n    }\n  }\n\n  private void writeOnProbes(DataOutputStream dos) throws IOException {\n    Collection<OnProbe> onProbes = delegate.getOnProbes();\n    int cnt = onProbes.size();\n    dos.writeInt(cnt);\n    for (OnProbe op : onProbes) {\n      dos.writeUTF(op.getNamespace());\n      dos.writeUTF(op.getName());\n      dos.writeUTF(op.getTargetDescriptor());\n      dos.writeUTF(op.getTargetName());\n      dos.writeInt(op.getClassNameParameter());\n      dos.writeInt(op.getDurationParameter());\n      dos.writeInt(op.getMethodParameter());\n      dos.writeInt(op.getReturnParameter());\n      dos.writeInt(op.getSelfParameter());\n      dos.writeInt(op.getTargetInstanceParameter());\n      dos.writeInt(op.getTargetMethodOrFieldParameter());\n      dos.writeBoolean(op.isMethodFqn());\n      dos.writeBoolean(op.isTargetMethodOrFieldFqn());\n    }\n  }\n\n  private void writeFullData(DataOutputStream dos) throws IOException {\n    dos.writeInt(fullData.length);\n    dos.write(fullData);\n  }\n\n  private void writeDataHolderClass(DataOutputStream dos) throws IOException {\n    dos.writeInt(dataHolder.length);\n    dos.write(dataHolder);\n  }\n\n  private void writeCallees(DataOutputStream dos) throws IOException {\n    int cnt = 0;\n    for (Set<String> callees : calleeMap.values()) {\n      if (!callees.isEmpty()) {\n        cnt++;\n      }\n    }\n    dos.writeInt(cnt);\n    for (Map.Entry<String, Set<String>> e : calleeMap.entrySet()) {\n      if (!e.getValue().isEmpty()) {\n        dos.writeUTF(e.getKey());\n        dos.writeInt(e.getValue().size());\n        for (String c : e.getValue()) {\n          dos.writeUTF(c);\n        }\n      }\n    }\n  }\n\n  private void writePermissions(DataOutputStream dos) throws IOException {\n    Set<Permission> perms = delegate.getRequiredPermissions();\n    dos.writeInt(perms.size());\n    for (Permission perm : perms) {\n      dos.writeUTF(perm.name());\n    }\n  }\n\n  @Override\n  public Collection<OnMethod> getApplicableHandlers(BTraceClassReader cr) {\n    return delegate.getApplicableHandlers(cr);\n  }\n\n  @Override\n  public byte[] getFullBytecode() {\n    return fullData;\n  }\n\n  @Override\n  public byte[] getDataHolderBytecode() {\n    return dataHolder;\n  }\n\n  @Override\n  public String getClassName() {\n    return delegate.getClassName(false);\n  }\n\n  @Override\n  public String getClassName(boolean internal) {\n    return delegate.getClassName(internal);\n  }\n\n  @Override\n  public boolean isClassRenamed() {\n    return delegate.isClassRenamed();\n  }\n\n  @Override\n  public boolean isTransforming() {\n    return delegate.isTransforming();\n  }\n\n  @Override\n  public boolean isVerified() {\n    if (factory.getSettings().isTrusted()) {\n      return true;\n    }\n    if (triedVerify.compareAndSet(false, true)) {\n      try {\n        verifyBytecode();\n        return true;\n      } catch (VerifierException e) {\n        if (Boolean.getBoolean(\"btrace.verifier.dump\")) {\n          System.err.println(\"[BTRACE VERIFY] \" + e.getMessage());\n        }\n        log.debug(\"Class '{}' verification failed\", getClassName(), e);\n      }\n    }\n    return false;\n  }\n\n  @Override\n  public void notifyTransform(String className) {\n    if (rt != null && factory.getSettings().isTrackRetransforms()) {\n      rt.sendCommand(new RetransformClassNotification(className.replace('/', '.')));\n    }\n  }\n\n  @Override\n  public Iterable<OnMethod> onmethods() {\n    return delegate.onmethods();\n  }\n\n  public Collection<OnMethod> getOnMethods() {\n    return delegate.getOnMethods();\n  }\n\n  @Override\n  public Iterable<OnProbe> onprobes() {\n    return delegate.onprobes();\n  }\n\n  @Override\n  public Class<?> register(BTraceRuntime.Impl rt, BTraceTransformer t) {\n    byte[] code = dataHolder;\n    if (debug.isDumpClasses()) {\n      debug.dumpClass(delegate.getClassName(true) + \"_bcp\", code);\n    }\n    Class<?> clz = delegate.defineClass(rt, code);\n    HandlerRepositoryImpl.registerProbe(this);\n    t.register(this);\n    transformer = t;\n    this.rt = rt;\n    return clz;\n  }\n\n  @Override\n  public Class<?> getProbeClass() {\n    return delegate.getProbeClass();\n  }\n\n  @Override\n  public java.lang.invoke.MethodHandle getCachedHandler(\n      String handlerName, java.lang.invoke.MethodType type) {\n    return delegate.getCachedHandler(handlerName, type);\n  }\n\n  @Override\n  public void cacheHandler(\n      String handlerName, java.lang.invoke.MethodType type, java.lang.invoke.MethodHandle mh) {\n    delegate.cacheHandler(handlerName, type, mh);\n  }\n\n  @Override\n  public void unregister() {\n    HandlerRepositoryImpl.unregisterProbe(this);\n    if (transformer != null && isTransforming()) {\n      if (log.isDebugEnabled()) {\n        log.debug(\"onExit: removing transformer for {}\", getClassName());\n      }\n      transformer.unregister(this);\n    }\n    delegate.clearProbeClass();\n    rt = null;\n  }\n\n  @Override\n  public boolean willInstrument(Class<?> clz) {\n    return delegate.willInstrument(clz);\n  }\n\n  @Override\n  public void checkVerified() {\n    if (!preverified) {\n      isVerified();\n    }\n  }\n\n  @Override\n  public void copyHandlers(ClassVisitor copyingVisitor) {\n    ClassReader cr = new ClassReader(fullData);\n    Set<String> copiedMethods = new HashSet<>();\n    for (OnMethod om : onmethods()) {\n      if (om.isCalled()) {\n        String mid = CallGraph.methodId(om.getTargetName(), om.getTargetDescriptor());\n        copiedMethods.add(mid);\n        Set<String> callees = calleeMap.get(mid);\n        if (callees != null) {\n          copiedMethods.addAll(calleeMap.get(mid));\n        }\n      }\n    }\n    cr.accept(\n        new ClassVisitor(ASM9) {\n          @Override\n          public void visit(\n              int version,\n              int access,\n              String name,\n              String signature,\n              String superName,\n              String[] interfaces) {\n            copyingVisitor.visit(version, access, name, signature, superName, interfaces);\n          }\n\n          @Override\n          public MethodVisitor visitMethod(\n              int access, String name, String desc, String signature, String[] exceptions) {\n            String mid = CallGraph.methodId(name, desc);\n            if (copiedMethods.contains(mid)) {\n              return copyingVisitor.visitMethod(\n                  ACC_PRIVATE | ACC_STATIC,\n                  getActionPrefix() + name,\n                  desc.replace(Constants.ANYTYPE_DESC, Constants.OBJECT_DESC),\n                  signature != null\n                      ? signature.replace(Constants.ANYTYPE_DESC, Constants.OBJECT_DESC)\n                      : null,\n                  exceptions);\n            }\n            return super.visitMethod(access, name, desc, signature, exceptions);\n          }\n        },\n        0);\n  }\n\n  @Override\n  public void applyArgs(ArgsMap argsMap) {\n    delegate.applyArgs(argsMap);\n  }\n\n  @Override\n  public BTraceRuntime.Impl getRuntime() {\n    return rt;\n  }\n\n  @Override\n  public String getActionPrefix() {\n    return delegate.getActionPrefix();\n  }\n\n  @Override\n  public Set<Permission> getRequiredPermissions() {\n    return delegate.getRequiredPermissions();\n  }\n\n  private void upgradeBytecode() {\n    fullData = ProbeUpgradeVisitor_1_2.upgrade(new ClassReader(fullData));\n    dataHolder = ProbeUpgradeVisitor_1_2.upgrade(new ClassReader(dataHolder));\n  }\n\n  private void verifyBytecode() throws VerifierException {\n    ClassReader cr = new ClassReader(fullData);\n    cr.accept(\n        new ClassVisitor(ASM9) {\n          private String className;\n\n          @Override\n          public void visit(\n              int version,\n              int access,\n              String name,\n              String signature,\n              String superName,\n              String[] interfaces) {\n            if ((access & ACC_INTERFACE) != 0 || (access & ACC_ENUM) != 0) {\n              Verifier.reportError(\"btrace.program.should.be.class\");\n            }\n            if ((access & ACC_PUBLIC) == 0) {\n              Verifier.reportError(\"class.should.be.public\", name);\n            }\n\n            if (!superName.equals(Constants.OBJECT_INTERNAL)) {\n              Verifier.reportError(\"object.superclass.required\", superName);\n            }\n            if (interfaces != null && interfaces.length > 0) {\n              Verifier.reportError(\"no.interface.implementation\");\n            }\n            className = name;\n            super.visit(version, access, name, signature, superName, interfaces);\n          }\n\n          @Override\n          public void visitInnerClass(String name, String outerName, String innerName, int access) {\n            if (className.equals(outerName)) {\n              Verifier.reportError(\"no.nested.class\");\n            }\n          }\n\n          @Override\n          public void visitOuterClass(String s, String s1, String s2) {\n            Verifier.reportError(\"no.outer.class\");\n          }\n\n          @Override\n          public FieldVisitor visitField(\n              int access, String name, String desc, String sig, Object dflt) {\n            if ((access & ACC_STATIC) == 0) {\n              Verifier.reportError(\"agent.no.instance.variables\", name);\n            }\n            return super.visitField(access, name, desc, sig, dflt);\n          }\n\n          @Override\n          public MethodVisitor visitMethod(\n              int access, String methodName, String desc, String sig, String[] exceptions) {\n            if ((access & ACC_SYNCHRONIZED) != 0) {\n              Verifier.reportError(\n                  \"no.synchronized.methods\",\n                  TypeUtils.descriptorToSimplified(desc, className, methodName));\n            }\n\n            if (!methodName.equals(Constants.CONSTRUCTOR)) {\n              if ((access & ACC_STATIC) == 0) {\n                Verifier.reportError(\n                    \"no.instance.method\",\n                    TypeUtils.descriptorToSimplified(desc, className, methodName));\n              }\n            }\n\n            if (methodName.equals(Constants.CLASS_INITIALIZER)) {\n              return super.visitMethod(access, methodName, desc, sig, exceptions);\n            }\n\n            return new MethodVisitor(\n                ASM9, super.visitMethod(access, methodName, desc, sig, exceptions)) {\n              private final Map<Label, Label> labels = new HashMap<>();\n\n              @Override\n              public void visitFieldInsn(int opcode, String owner, String name, String desc) {\n                if (opcode == PUTFIELD) {\n                  Verifier.reportError(\"no.assignment\");\n                }\n\n                if (opcode == PUTSTATIC) {\n                  if (!owner.equals(className)) {\n                    Verifier.reportError(\"no.assignment\");\n                  }\n                }\n                super.visitFieldInsn(opcode, owner, name, desc);\n              }\n\n              @Override\n              public void visitInsn(int opcode) {\n                switch (opcode) {\n                  case IASTORE:\n                  case LASTORE:\n                  case FASTORE:\n                  case DASTORE:\n                  case AASTORE:\n                  case BASTORE:\n                  case CASTORE:\n                  case SASTORE:\n                    Verifier.reportError(\"no.assignment\");\n                    break;\n                  case ATHROW:\n                    Verifier.reportError(\"no.throw\");\n                    break;\n                  case MONITORENTER:\n                  case MONITOREXIT:\n                    Verifier.reportError(\"no.synchronized.blocks\");\n                    break;\n                }\n                super.visitInsn(opcode);\n              }\n\n              @Override\n              public void visitIntInsn(int opcode, int operand) {\n                if (opcode == NEWARRAY) {\n                  Verifier.reportError(\"no.array.creation\");\n                }\n                super.visitIntInsn(opcode, operand);\n              }\n\n              @Override\n              public void visitJumpInsn(int opcode, Label label) {\n                if (labels.get(label) != null) {\n                  Verifier.reportError(\"no.loops\");\n                }\n                super.visitJumpInsn(opcode, label);\n              }\n\n              @Override\n              public void visitMethodInsn(\n                  int opcode, String owner, String name, String desc, boolean itfc) {\n                switch (opcode) {\n                  case INVOKEVIRTUAL:\n                    if (MethodVerifier.isPrimitiveWrapper(owner)\n                        && MethodVerifier.isUnboxMethod(name)) {\n                      // allow primitive type unbox methods.\n                      // These calls are generated by javac for auto-unboxing `\n                      // and can't be caught by source AST analyzer as well.\n                    } else if (owner.equals(Constants.STRING_BUILDER_INTERNAL)) {\n                      // allow string concatenation via StringBuilder\n                    } else if (owner.equals(Constants.THREAD_LOCAL_INTERNAL)) {\n                      // allow ThreadLocal methods\n                    } else if (owner.equals(Constants.BTRACERTACCESS_INTERNAL)) {\n                      // allow BTraceRuntimeAccess methods\n                    } else if (owner.equals(Constants.BTRACERTBRIDGE_INTERNAL)) {\n                      // allow BTraceRuntimeImplBase methods\n                    } else {\n                      if (!delegate.isServiceType(owner)) {\n                        Verifier.reportError(\"no.method.calls\", owner + \".\" + name + desc);\n                      }\n                    }\n                    break;\n                  case INVOKEINTERFACE:\n                    // allow BTraceRuntimeBridge interface methods (leave(), enter(), etc.)\n                    if (!owner.equals(Constants.BTRACERTBRIDGE_INTERNAL)\n                        && !delegate.isServiceType(owner)) {\n                      Verifier.reportError(\"no.method.calls\", owner + \".\" + name + desc);\n                    }\n                    break;\n                  case INVOKESPECIAL:\n                    if (owner.equals(Constants.OBJECT_INTERNAL)\n                        && name.equals(Constants.CONSTRUCTOR)) {\n                      // allow object initializer\n                    } else if (owner.equals(Constants.STRING_BUILDER_INTERNAL)) {\n                      // allow string concatenation via StringBuilder\n                    } else if (owner.equals(Constants.THREAD_LOCAL_INTERNAL)) {\n                      // allow ThreadLocal methods\n                    } else if (delegate.isServiceType(owner)) {\n                      // allow services invocations\n                    } else {\n                      Verifier.reportError(\"no.method.calls\", owner + \".\" + name + desc);\n                    }\n                    break;\n                  case INVOKESTATIC:\n                    if (!owner.startsWith(\"org/openjdk/btrace/\") && !owner.equals(className)) {\n                      if (\"valueOf\".equals(name) && MethodVerifier.isPrimitiveWrapper(owner)) {\n                        // allow primitive wrapper boxing methods.\n                        // These calls are generated by javac for autoboxing\n                        // and can't be caught sourc AST analyzer as well.\n                      } else {\n                        Verifier.reportError(\"no.method.calls\", owner + \".\" + name + desc);\n                      }\n                    }\n                    break;\n                }\n                super.visitMethodInsn(opcode, owner, name, desc, itfc);\n              }\n\n              @Override\n              public void visitMultiANewArrayInsn(String desc, int dims) {\n                Verifier.reportError(\"no.array.creation\");\n              }\n\n              @Override\n              public void visitTypeInsn(int opcode, String desc) {\n                if (opcode == ANEWARRAY) {\n                  Verifier.reportError(\"no.array.creation\", desc);\n                }\n                if (opcode == NEW) {\n                  // allow StringBuilder creation for string concatenation\n                  if (!desc.equals(Constants.STRING_BUILDER_INTERNAL)\n                      && !delegate.isServiceType(desc)) {\n                    Verifier.reportError(\"no.new.object\", desc);\n                  }\n                }\n                super.visitTypeInsn(opcode, desc);\n              }\n\n              @Override\n              public void visitVarInsn(int opcode, int var) {\n                if (opcode == RET) {\n                  Verifier.reportError(\"no.try\");\n                }\n                super.visitVarInsn(opcode, var);\n              }\n            };\n          }\n        },\n        ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);\n  }\n\n  private static final class Handler {\n    private final String name;\n    private final String desc;\n\n    public Handler(String name, String desc) {\n      this.name = name;\n      this.desc = desc;\n    }\n\n    @Override\n    public int hashCode() {\n      int hash = 7;\n      hash = 29 * hash + Objects.hashCode(name);\n      hash = 29 * hash + Objects.hashCode(desc);\n      return hash;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n      if (this == obj) {\n        return true;\n      }\n      if (obj == null) {\n        return false;\n      }\n      if (getClass() != obj.getClass()) {\n        return false;\n      }\n      Handler other = (Handler) obj;\n      if (!Objects.equals(name, other.name)) {\n        return false;\n      }\n      return Objects.equals(desc, other.desc);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbeSupport.java",
    "content": "/*\n * Copyright (c) 2017,2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\npackage org.openjdk.btrace.instr;\n\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodType;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicReferenceFieldUpdater;\nimport java.util.regex.Pattern;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.runtime.BTraceRuntimeAccess;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.openjdk.btrace.instr.ClassFilter.isSubTypeOf;\n\npublic final class BTraceProbeSupport {\n  private static final Logger log = LoggerFactory.getLogger(BTraceProbeSupport.class);\n\n  private volatile String actionPrefix = null;\n  private static final AtomicReferenceFieldUpdater<BTraceProbeSupport, String> actionPrefixUpdate = AtomicReferenceFieldUpdater.newUpdater(BTraceProbeSupport.class, String.class, \"actionPrefix\");\n  private final List<OnMethod> onMethods;\n  private final List<OnProbe> onProbes;\n  private final Map<String, String> serviceFields;\n  private final EnumSet<Permission> requiredPermissions;\n\n  private final Object filterLock = new Object();\n  private volatile ClassFilter filter;\n  private boolean trustedScript = false;\n  private boolean classRenamed = false;\n  private String className, origName;\n  private volatile Class<?> probeClass;\n\n  /**\n   * Per-probe handler {@link MethodHandle} cache. Holding it on the probe means it dies\n   * with the probe object — no cross-probe scan on unregister, and no accidental retention\n   * of the probe's defined {@code Class<?>} / {@code ClassLoader} via a static map outlasting\n   * the probe.\n   *\n   * <p>The key omits the probe name (redundant given the cache is per-probe). Sized small on\n   * purpose: a typical probe has O(10) handlers.\n   */\n  private final Map<HandlerSubKey, MethodHandle> handlerCache = new ConcurrentHashMap<>();\n\n  BTraceProbeSupport() {\n    onMethods = new ArrayList<>();\n    onProbes = new ArrayList<>();\n    serviceFields = new HashMap<>();\n    requiredPermissions = EnumSet.noneOf(Permission.class);\n  }\n\n  void setClassName(String name) {\n    origName = name;\n    String clientName = BTraceRuntimeAccess.getClientName(name);\n    className = clientName != null ? clientName : name;\n    classRenamed = !className.equals(name);\n  }\n\n  String getClassName(boolean internal) {\n    return internal ? className : className.replace(\"/\", \".\");\n  }\n\n  String getOrigName() {\n    return origName;\n  }\n\n  boolean isClassRenamed() {\n    return classRenamed;\n  }\n\n  String translateOwner(String owner) {\n    if (owner.equals(origName)) {\n      return getClassName(true);\n    }\n    return owner;\n  }\n\n  boolean isTransforming() {\n    return !onMethods.isEmpty();\n  }\n\n  Collection<OnMethod> getApplicableHandlers(BTraceClassReader cr) {\n    Collection<OnMethod> applicables = new ArrayList<>(onMethods.size());\n    String targetName = cr.getJavaClassName();\n\n    outer:\n    for (OnMethod om : onMethods) {\n      String probeClass = om.getClazz();\n      if (probeClass == null || probeClass.isEmpty()) continue;\n\n      if (probeClass.equals(targetName)) {\n        applicables.add(om);\n        continue;\n      }\n      // Check regex match\n      if (om.isClassRegexMatcher() && !om.isClassAnnotationMatcher()) {\n        Pattern p = om.getClassPattern();\n        if (p != null && p.matcher(targetName).matches()) {\n          applicables.add(om);\n          continue;\n        }\n      }\n      if (om.isClassAnnotationMatcher()) {\n        Collection<String> annoTypes = cr.getAnnotationTypes();\n        if (om.isClassRegexMatcher()) {\n          Pattern p = om.getClassPattern();\n          if (p != null) {\n            for (String annoType : annoTypes) {\n              if (p.matcher(annoType).matches()) {\n                applicables.add(om);\n                continue outer;\n              }\n            }\n          }\n        } else {\n          if (annoTypes.contains(probeClass)) {\n            applicables.add(om);\n            continue;\n          }\n        }\n      }\n      // And, finally, check the class hierarchy\n      if (om.isSubtypeMatcher()) {\n        // internal name of super type.\n        if (isSubTypeOf(cr.getClassName(), cr.getClassLoader(), probeClass)) {\n          applicables.add(om);\n        }\n      }\n    }\n    return applicables;\n  }\n\n  Collection<OnMethod> getOnMethods() {\n    return Collections.unmodifiableCollection(onMethods);\n  }\n\n  Collection<OnProbe> getOnProbes() {\n    return Collections.unmodifiableCollection(onProbes);\n  }\n\n  Iterable<OnMethod> onmethods() {\n    return () -> Collections.unmodifiableCollection(onMethods).iterator();\n  }\n\n  Iterable<OnProbe> onprobes() {\n    return () -> onProbes.iterator();\n  }\n\n  Map<String, String> serviceFields() {\n    return Collections.unmodifiableMap(serviceFields);\n  }\n\n  boolean isServiceType(String typeName) {\n    // First check if it's a direct service type (e.g., MetricsService)\n    if (serviceFields.containsValue(typeName)) {\n      return true;\n    }\n    // Check if it's in a sub-package of any service type's package\n    // This allows return types from service methods (e.g., HistogramMetric, HistogramSnapshot)\n    // without hardcoding specific packages - we infer allowed packages from injected services\n    for (String serviceType : serviceFields.values()) {\n      // Extract package by removing the class name (everything after the last '/')\n      int lastSlash = serviceType.lastIndexOf('/');\n      if (lastSlash > 0) {\n        String servicePackage = serviceType.substring(0, lastSlash);\n        // Allow classes in the same package or sub-packages of the service\n        // This makes the verifier cooperate with the extension system automatically\n        if (typeName.startsWith(servicePackage + \"/\")) {\n          return true;\n        }\n      }\n    }\n    return false;\n  }\n\n  boolean isFieldInjected(String name) {\n    return serviceFields.containsKey(name);\n  }\n\n  void addOnMethod(OnMethod om) {\n    onMethods.add(om);\n  }\n\n  void addOnProbe(OnProbe op) {\n    onProbes.add(op);\n  }\n\n  void addServiceField(String fldName, String svcType) {\n    serviceFields.put(fldName, svcType);\n  }\n\n  void addRequiredPermission(Permission permission) {\n    requiredPermissions.add(permission);\n  }\n\n  Set<Permission> getRequiredPermissions() {\n    return Collections.unmodifiableSet(requiredPermissions);\n  }\n\n  boolean willInstrument(Class clz) {\n    return getClassFilter().isCandidate(clz);\n  }\n\n  private ClassFilter getClassFilter() {\n    synchronized (filterLock) {\n      if (filter == null) {\n        filter = new ClassFilter(onmethods());\n      }\n      return filter;\n    }\n  }\n\n  void setTrusted() {\n    trustedScript = true;\n  }\n\n  boolean isTrusted() {\n    return trustedScript;\n  }\n\n  Class<?> getProbeClass() {\n    return probeClass;\n  }\n\n  void clearProbeClass() {\n    this.probeClass = null;\n    // Drop cached MethodHandles — they resolve into the now-released probe Class and would\n    // otherwise keep it (and its ClassLoader) reachable across a detach.\n    handlerCache.clear();\n  }\n\n  MethodHandle getCachedHandler(String handlerName, MethodType type) {\n    return handlerCache.get(new HandlerSubKey(handlerName, type));\n  }\n\n  void cacheHandler(String handlerName, MethodType type, MethodHandle mh) {\n    handlerCache.put(new HandlerSubKey(handlerName, type), mh);\n  }\n\n  /**\n   * Cache key for the per-probe handler cache. The probe component is implicit (the map\n   * lives on the probe) so we only carry {@code (handlerName, type)}. Hash is precomputed\n   * because the key is recomputed on every resolve.\n   */\n  private static final class HandlerSubKey {\n    final String handler;\n    final MethodType type;\n    private final int hash;\n\n    HandlerSubKey(String handler, MethodType type) {\n      this.handler = handler;\n      this.type = type;\n      this.hash = handler.hashCode() * 31 + type.hashCode();\n    }\n\n    @Override\n    public int hashCode() {\n      return hash;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n      if (this == o) return true;\n      if (!(o instanceof HandlerSubKey)) return false;\n      HandlerSubKey k = (HandlerSubKey) o;\n      return hash == k.hash && handler.equals(k.handler) && type.equals(k.type);\n    }\n  }\n\n  Class<?> defineClass(BTraceRuntime.Impl rt, byte[] code) {\n    // This extra BTraceRuntime.enter is needed to\n    // check whether we have already entered before.\n    boolean enteredHere = BTraceRuntime.enter();\n    try {\n      // The trace class static initializer needs to be run\n      // without BTraceRuntime.enter(). Please look at the\n      // static initializer code of trace class.\n      BTraceRuntime.leave();\n      if (log.isDebugEnabled()) {\n        log.debug(\"about to defineClass {}\", getClassName(false));\n      }\n      Class<?> clz = rt.defineClass(code);\n      if (log.isDebugEnabled()) {\n        log.debug(\"defineClass succeeded for {}\", getClassName(false));\n      }\n      this.probeClass = clz;\n      return clz;\n    } finally {\n      // leave BTraceRuntime enter state as it was before\n      // we started executing this method.\n      if (!enteredHere) BTraceRuntime.enter();\n    }\n  }\n\n  void applyArgs(ArgsMap argsMap) {\n    for (OnMethod om : onMethods) {\n      om.applyArgs(argsMap);\n    }\n  }\n\n  String getActionPrefix() {\n    return actionPrefixUpdate.updateAndGet(this, prefix -> {\n      if (prefix == null) {\n        prefix = Constants.BTRACE_METHOD_PREFIX +\n                getClassName(true).replace('/', '$') + \"$\";\n      }\n      return prefix;\n    });\n  }\n\n  @Override\n  public String toString() {\n    return \"BTraceProbeSupport{\"\n        + \"onMethods=\"\n        + onMethods\n        + \", onProbes=\"\n        + onProbes\n        + \", trustedScript=\"\n        + trustedScript\n        + \", serviceFields=\"\n        + serviceFields\n        + '}';\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceTransformer.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.DebugSupport;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.instrument.ClassFileTransformer;\nimport java.lang.instrument.IllegalClassFormatException;\nimport java.security.ProtectionDomain;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\nimport java.util.regex.Pattern;\n\n/**\n * The single entry point for class transformation.\n *\n * <p>When a class is to be transformed all the registered {@linkplain BTraceProbe} instances are\n * asked for the appropriate instrumentation. When there are no registered probes or none of the\n * registered probes is able to instrument the class it will not be transformed.\n *\n * @author Jaroslav Bachorik\n * @since 1.3.5\n */\n@SuppressWarnings(\"RedundantThrows\")\npublic final class BTraceTransformer implements ClassFileTransformer {\n  private static final Logger log = LoggerFactory.getLogger(BTraceTransformer.class);\n\n  private final DebugSupport debug;\n  private final ReentrantReadWriteLock setupLock = new ReentrantReadWriteLock();\n  private final Collection<BTraceProbe> probes = new ArrayList<>(3);\n  private final Filter filter = new Filter();\n\n  public BTraceTransformer(DebugSupport d) {\n    debug = d;\n  }\n\n  /*\n   * Certain classes like java.lang.ThreadLocal and it's\n   * inner classes, java.lang.Object cannot be safely\n   * instrumented with BTrace. This is because BTrace uses\n   * ThreadLocal class to check recursive entries due to\n   * BTrace's own functions. But this leads to infinite recursions\n   * if BTrace instruments java.lang.ThreadLocal for example.\n   * For now, we avoid such classes till we find a solution.\n   */\n  private static boolean isSensitiveClass(String name) {\n    return ClassFilter.isSensitiveClass(name);\n  }\n\n  // JDK lambda wrapper names from LambdaMetafactory:\n  //   JDK 8:   <owner>$$Lambda$<N>                    (e.g. Main$$Lambda$36)\n  //   JDK 11+: <owner>$$Lambda$<N>/0x<hex>            (hidden-class suffix)\n  // Both forms are recognised by the \"$$Lambda$\" infix followed by digits.\n  static boolean isSyntheticLambda(String internalName) {\n    if (internalName == null) return false;\n    int idx = internalName.indexOf(\"$$Lambda$\");\n    if (idx < 0) return false;\n    int digitStart = idx + \"$$Lambda$\".length();\n    if (digitStart >= internalName.length()) return false;\n    // Next char must be a digit (the Lambda serial number)\n    return Character.isDigit(internalName.charAt(digitStart));\n  }\n\n  public void register(BTraceProbe p) {\n    try {\n      setupLock.writeLock().lock();\n      probes.add(p);\n      for (OnMethod om : p.onmethods()) {\n        filter.add(om);\n      }\n    } finally {\n      setupLock.writeLock().unlock();\n    }\n  }\n\n  public final void unregister(BTraceProbe p) {\n    try {\n      setupLock.writeLock().lock();\n      probes.remove(p);\n      for (OnMethod om : p.onmethods()) {\n        filter.remove(om);\n      }\n    } finally {\n      setupLock.writeLock().unlock();\n    }\n  }\n\n  @Override\n  public byte[] transform(\n      ClassLoader loader,\n      String className,\n      Class<?> classBeingRedefined,\n      ProtectionDomain protectionDomain,\n      byte[] classfileBuffer)\n      throws IllegalClassFormatException {\n    try {\n      setupLock.readLock().lock();\n\n      // Skip JVM-synthesized classes that have no binary name (JDK 8\n      // Unsafe.defineAnonymousClass host-anonymous classes, JDK 15+ hidden\n      // classes). These are never a user-intended tracing target: a\n      // @OnMethod(clazz=\"<pattern>\") matcher targets classes the user\n      // authored, not the VM's lambda/LambdaForm scaffolding. Instrumenting\n      // them also re-enters the invokedynamic machinery that the probe\n      // dispatch itself uses, leading to unbounded recursion on JDK 8.\n      if (className == null) {\n        return null;\n      }\n\n      // A special case for patching the Indy linking in order to be able to safely skip\n      // BTrace probes while linking is still in progress.\n      if (className.equals(\"java/lang/invoke/MethodHandleNatives\")) {\n        byte[] transformed = null;\n        try {\n          debug.dumpClass(className.replace('.', '/') + \"_orig\", classfileBuffer);\n          transformed = LinkerInstrumentor.addGuard(classfileBuffer);\n          debug.dumpClass(className.replace('.', '/'), transformed);\n        } catch (Throwable t) {\n          log.debug(\"Failed to instrument indy linking\", t);\n        }\n        return transformed;\n      }\n\n      // Skip JVM-synthesized classes: reflection accessors (sun/reflect/Generated*,\n      // jdk/internal/reflect/Generated*) and lambda wrappers (LambdaMetafactory names\n      // them \"<owner>$$Lambda$N\" on JDK 8 and \"<owner>$$Lambda$N/0x<hex>\" on JDK 11+).\n      // Instrumenting these serves no tracing purpose — they are 1:1 trampolines to a\n      // target Method or a captured functional method the user can trace directly —\n      // and it recursively re-enters the invokedynamic/LambdaMetafactory machinery\n      // that the probe dispatch path relies on.\n      if (className.startsWith(\"sun/reflect/Generated\")\n          || className.startsWith(\"jdk/internal/reflect/Generated\")\n          || isSyntheticLambda(className)) {\n        return null;\n      }\n\n      if (probes.isEmpty()) return null;\n      if ((loader == null || loader.equals(ClassLoader.getSystemClassLoader()))\n          && isSensitiveClass(className)) {\n        if (log.isDebugEnabled()) {\n          log.debug(\"skipping transform for BTrace class {}\", className); // NOI18N\n        }\n        return null;\n      }\n\n      if (filter.matchClass(className) == Filter.Result.FALSE) return null;\n\n      boolean entered = BTraceRuntime.enter();\n      try {\n        if (debug.isDumpClasses()) {\n          debug.dumpClass(className.replace('.', '/') + \"_orig\", classfileBuffer);\n        }\n        BTraceClassReader cr = InstrumentUtils.newClassReader(loader, classfileBuffer);\n        BTraceClassWriter cw = InstrumentUtils.newClassWriter(cr);\n        for (BTraceProbe p : probes) {\n          p.notifyTransform(className);\n          cw.addInstrumentor(p, loader);\n        }\n        byte[] transformed = cw.instrument();\n        if (transformed == null) {\n          // no instrumentation necessary\n          if (log.isDebugEnabled()) {\n            log.debug(\"skipping class {}\", cr.getJavaClassName());\n          }\n          return classfileBuffer;\n        } else {\n          if (log.isDebugEnabled()) {\n            log.debug(\"transformed class {}\", cr.getJavaClassName());\n          }\n          // Optional: verify transformed class via ASM in tests.\n          if (Boolean.getBoolean(\"btrace.verify.transformed\") && !Boolean.TRUE.equals(VerifyGuard.IN_PROGRESS.get())) {\n            boolean allow;\n            String filter = System.getProperty(\"btrace.verify.filter\");\n            if (filter != null && !filter.isEmpty()) {\n              allow = className.matches(filter);\n            } else {\n              allow = isAppClass(className);\n            }\n            if (allow) {\n              try {\n                VerifyGuard.IN_PROGRESS.set(Boolean.TRUE);\n                java.io.StringWriter sw = new java.io.StringWriter();\n                org.objectweb.asm.util.CheckClassAdapter.verify(\n                    new org.objectweb.asm.ClassReader(transformed),\n                    false,\n                    new java.io.PrintWriter(sw));\n                String report = sw.toString();\n                if (!report.isEmpty()) {\n                  log.warn(\"ASM verification issues for {}:\\n{}\", className, report);\n                } else if (log.isDebugEnabled()) {\n                  log.debug(\"ASM verification OK for {}\", className);\n                }\n              } catch (Throwable t) {\n                // Don't break transformation on verifier diagnostics\n                log.warn(\"ASM verification failed for {}: {}\", className, t.toString());\n              } finally {\n                VerifyGuard.IN_PROGRESS.remove();\n              }\n            }\n          }\n          if (debug.isDumpClasses()) {\n            debug.dumpClass(className.replace('.', '/'), transformed);\n          }\n        }\n        return transformed;\n      } catch (Throwable th) {\n        log.warn(\"Failed to transform class {}\", className, th);\n        throw th;\n      } finally {\n        if (entered) {\n          BTraceRuntime.leave();\n        }\n      }\n    } finally {\n      setupLock.readLock().unlock();\n    }\n  }\n\n  // Helper guard and app-class predicate for verifier\n  static final class VerifyGuard {\n    static final ThreadLocal<Boolean> IN_PROGRESS = ThreadLocal.withInitial(() -> Boolean.FALSE);\n  }\n\n  private static boolean isAppClass(String internalName) {\n    if (internalName == null) return false;\n    return !(internalName.startsWith(\"java/\") ||\n        internalName.startsWith(\"javax/\") ||\n        internalName.startsWith(\"jdk/\") ||\n        internalName.startsWith(\"sun/\") ||\n        internalName.startsWith(\"com/sun/\") ||\n        internalName.startsWith(\"org/ietf/\") ||\n        internalName.startsWith(\"org/omg/\") ||\n        internalName.startsWith(\"org/w3c/\") ||\n        internalName.startsWith(\"org/xml/\") ||\n        internalName.startsWith(\"org/openjdk/btrace/\"));\n  }\n\n  static class Filter {\n    private final Map<String, Integer> nameMap = new HashMap<>();\n    private final Map<Pattern, Integer> nameRegexMap = new HashMap<>();\n    private final Map<String, Pattern> patternCache = new ConcurrentHashMap<>();\n    private boolean isFast = true;\n    private boolean isRegex = false;\n\n    @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n    private static <K> void addToMap(Map<K, Integer> map, K name) {\n      synchronized (map) {\n        map.merge(name, 1, Integer::sum);\n      }\n    }\n\n    @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n    private static <K> void removeFromMap(Map<K, Integer> map, K name) {\n      synchronized (map) {\n        Integer i = map.get(name);\n        if (i == null) {\n          return;\n        }\n        int freq = i - 1;\n        if (freq == 0) {\n          map.remove(name);\n        }\n      }\n    }\n\n    void add(OnMethod om) {\n      if (om.isSubtypeMatcher() || om.isClassAnnotationMatcher()) {\n        isFast = false;\n      } else {\n        if (om.isClassRegexMatcher()) {\n          isRegex = true;\n          String name = om.getClazz().replace(\"\\\\.\", \"/\");\n          Pattern pattern = patternCache.computeIfAbsent(name, Pattern::compile);\n          addToMap(nameRegexMap, pattern);\n        } else {\n          String name = om.getClazz().replace('.', '/');\n          addToMap(nameMap, name);\n        }\n      }\n    }\n\n    void remove(OnMethod om) {\n      String name = om.getClazz().replace('.', '/');\n      if (!(om.isSubtypeMatcher() || om.isClassAnnotationMatcher())) {\n        if (om.isClassRegexMatcher()) {\n          Pattern pattern = patternCache.get(name);\n          if (pattern != null) {\n            removeFromMap(nameRegexMap, pattern);\n          }\n        } else {\n          removeFromMap(nameMap, name);\n        }\n      }\n    }\n\n    public Result matchClass(String className) {\n      if (isFast) {\n        synchronized (nameMap) {\n          if (nameMap.containsKey(className)) {\n            return Result.TRUE;\n          }\n        }\n        if (isRegex) {\n          synchronized (nameRegexMap) {\n            for (Pattern p : nameRegexMap.keySet()) {\n              if (p.matcher(className).matches()) {\n                return Result.TRUE;\n              }\n            }\n          }\n        }\n        return Result.FALSE;\n      }\n      return Result.MAYBE;\n    }\n\n    enum Result {\n      TRUE,\n      FALSE,\n      MAYBE\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/BailoutException.java",
    "content": "package org.openjdk.btrace.instr;\n\n/**\n * Dummy, non-stack-collecting runtime exception. It is used for execution control in ClassReader\n * instances in order to avoid processing the complete class file when the relevant info is\n * available right at the beginning of parsing.\n */\nfinal class BailoutException extends RuntimeException {\n  /** Shared instance to optimize the cost of throwing */\n  static final BailoutException INSTANCE = new BailoutException();\n\n  private BailoutException() {}\n\n  @Override\n  public synchronized Throwable fillInStackTrace() {\n    // we don't need the stack here\n    return this;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/CallGraph.java",
    "content": "/*\n * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport java.util.ArrayDeque;\nimport java.util.Collections;\nimport java.util.Deque;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.regex.Pattern;\n\n/**\n * This class allows building an arbitrary graph caller-callee relationship\n *\n * @author Jaroslav Bachorik\n */\npublic final class CallGraph {\n  private static final Pattern MID_SPLIT_PTN = Pattern.compile(\"::\");\n  private final Map<String, Node> nodes = new HashMap<>();  // O(1) lookup index\n  private final Set<Node> startingNodes = new HashSet<>();\n\n  public static String methodId(String name, String desc) {\n    return name + \"::\" + desc;\n  }\n\n  public static String[] method(String methodId) {\n    if (methodId.contains(\"::\")) {\n      return MID_SPLIT_PTN.split(methodId);\n    }\n    return new String[0];\n  }\n\n  public void addEdge(String fromId, String toId) {\n    // O(1) lookup instead of O(n)\n    Node fromNode = nodes.computeIfAbsent(fromId, Node::new);\n    Node toNode = nodes.computeIfAbsent(toId, Node::new);\n\n    fromNode.addEdge(toNode);\n  }\n\n  public void addStarting(String methodId) {\n    // O(1) lookup\n    Node n = nodes.computeIfAbsent(methodId, Node::new);\n    startingNodes.add(n);\n  }\n\n  public boolean hasCycle() {\n    Set<Node> looped = findCycles();\n    if (looped.isEmpty()) {\n      return false;\n    }\n\n    Set<Node> checkingSet = new HashSet<>(looped);\n\n    checkingSet.retainAll(startingNodes);\n    if (!checkingSet.isEmpty()) {\n      // a starting node is part of the loop\n      return true;\n    }\n\n    Deque<Node> processingQueue = new ArrayDeque<>();\n    for (Node n : startingNodes) {\n      processingQueue.push(n);\n      do {\n        Node current = processingQueue.pop();\n        if (looped.contains(current)) {\n          // there is a path leading from a starting node to the detected loop\n          return true;\n        }\n        for (Edge e : current.outgoing) {\n          processingQueue.push(e.to);\n        }\n      } while (!processingQueue.isEmpty());\n    }\n    return false;\n  }\n\n  void callees(String name, String desc, Set<String> closure) {\n    collectOutgoings(methodId(name, desc), closure);\n  }\n\n  void callers(String name, String desc, Set<String> closure) {\n    collectIncomings(methodId(name, desc), closure);\n  }\n\n  private void collectOutgoings(String methodId, Set<String> closure) {\n    // O(1) lookup instead of O(n)\n    Node n = nodes.get(methodId);\n    if (n != null) {\n      for (Edge e : n.outgoing) {\n        if (!closure.contains(e.to.id)) {\n          closure.add(e.to.id);\n          collectOutgoings(e.to.id, closure);\n        }\n      }\n    }\n  }\n\n  private void collectIncomings(String methodId, Set<String> closure) {\n    // O(1) lookup instead of O(n)\n    Node n = nodes.get(methodId);\n    if (n != null) {\n      for (Edge e : n.incoming) {\n        if (!closure.contains(e.from.id)) {\n          closure.add(e.from.id);\n          collectIncomings(e.from.id, closure);\n        }\n      }\n    }\n  }\n\n  private Set<Node> findCycles() {\n    if (nodes.size() < 2) return Collections.emptySet();\n\n    Map<String, Node> checkingNodes = new HashMap<>();\n    for (Node n : nodes.values()) {\n      Node newN = checkingNodes.get(n.id);\n      if (newN == null) {\n        newN = new Node(n.id);\n        checkingNodes.put(n.id, newN);\n      }\n      for (Edge e : n.incoming) {\n        Node fromN = checkingNodes.get(e.from.id);\n        if (fromN == null) {\n          fromN = new Node(e.from.id);\n          checkingNodes.put(e.from.id, fromN);\n        }\n        Edge ee = new Edge(fromN, newN);\n        newN.addIncoming(ee);\n        fromN.addOutgoing(ee);\n      }\n      for (Edge e : n.outgoing) {\n        Node toN = checkingNodes.get(e.to.id);\n        if (toN == null) {\n          toN = new Node(e.to.id);\n          checkingNodes.put(e.to.id, toN);\n        }\n        Edge ee = new Edge(newN, toN);\n        newN.addOutgoing(ee);\n        toN.addIncoming(ee);\n      }\n    }\n\n    Set<Node> sortedNodes = new HashSet<>(checkingNodes.values());\n    // collect all terminal nodes\n    Deque<Node> terminalNodes = new ArrayDeque<>();\n    for (Node node : sortedNodes) {\n      if ((node.incoming.isEmpty() && !startingNodes.contains(node)) || node.outgoing.isEmpty()) {\n        terminalNodes.addLast(node);\n      }\n    }\n\n    // remove each terminal node from the graph and if the removal creates more terminal nodes\n    // add them all for processing\n    while (!terminalNodes.isEmpty()) {\n      Node n = terminalNodes.removeFirst();\n      sortedNodes.remove(n);\n      for (Edge e : new HashSet<>(n.incoming)) {\n        e.delete();\n        if (e.from.outgoing.isEmpty()) {\n          terminalNodes.addLast(e.from);\n        }\n      }\n      for (Edge e : new HashSet<>(n.outgoing)) {\n        e.delete();\n        if (e.to.incoming.isEmpty() && !startingNodes.contains(e.to)) {\n          terminalNodes.addLast(e.to);\n        }\n      }\n    }\n    return sortedNodes;\n  }\n\n  public static class Node {\n    private final String id;\n    private final Set<Edge> incoming = new HashSet<>();\n    private final Set<Edge> outgoing = new HashSet<>();\n\n    public Node(String id) {\n      this.id = id;\n    }\n\n    public void addIncoming(Edge e) {\n      incoming.add(e);\n    }\n\n    public void addOutgoing(Edge e) {\n      outgoing.add(e);\n    }\n\n    public void removeIncoming(Edge e) {\n      incoming.remove(e);\n    }\n\n    public void removeOutgoing(Edge e) {\n      outgoing.remove(e);\n    }\n\n    public void addEdge(Node to) {\n      Edge edge = new Edge(this, to);\n      this.addOutgoing(edge);\n      to.addIncoming(edge);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n      if (obj == null) {\n        return false;\n      }\n      if (getClass() != obj.getClass()) {\n        return false;\n      }\n      Node other = (Node) obj;\n      return Objects.equals(id, other.id);\n    }\n\n    @Override\n    public int hashCode() {\n      int hash = 7;\n      hash = 11 * hash + (id != null ? id.hashCode() : 0);\n      return hash;\n    }\n\n    @Override\n    public String toString() {\n      StringBuilder sb = new StringBuilder();\n      sb.append(\"Node{id='\").append(id).append(\"'}\");\n      sb.append(\"\\n\");\n      sb.append(\"incomming:\\n\");\n      sb.append(\"=============================\\n\");\n      for (Edge e : incoming) {\n        sb.append(e.from.id).append(\"\\n\");\n      }\n      sb.append(\"=============================\\n\");\n      sb.append(\"outgoing:\\n\");\n      for (Edge e : outgoing) {\n        sb.append(e.to.id).append(\"\\n\");\n      }\n      sb.append(\"=============================\\n\");\n\n      return sb.toString();\n    }\n  }\n\n  public static class Edge {\n    private final Node from;\n    private final Node to;\n\n    public Edge(Node from, Node to) {\n      this.from = from;\n      this.to = to;\n    }\n\n    public void delete() {\n      from.removeOutgoing(this);\n      to.removeIncoming(this);\n    }\n\n    @Override\n    @SuppressWarnings(\"ReferenceEquality\")\n    public boolean equals(Object obj) {\n      if (obj == null) {\n        return false;\n      }\n      if (getClass() != obj.getClass()) {\n        return false;\n      }\n      Edge other = (Edge) obj;\n      if (!Objects.equals(from, other.from)) {\n        return false;\n      }\n      return Objects.equals(to, other.to);\n    }\n\n    @Override\n    public int hashCode() {\n      int hash = 5;\n      hash = 37 * hash + (from != null ? from.hashCode() : 0);\n      hash = 37 * hash + (to != null ? to.hashCode() : 0);\n      return hash;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/CatchInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Type;\n\n/**\n * This visitor helps in inserting code whenever an exception is caught or finally block is reached.\n * The code to insert on exception catch or finally may be decided by derived class. By default,\n * this class inserts code to print a message.\n *\n * @author A. Sundararajan\n */\npublic class CatchInstrumentor extends MethodInstrumentor {\n  private final Map<Label, String> handlers = new HashMap<>();\n\n  public CatchInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  public void visitLabel(Label label) {\n    super.visitLabel(label);\n    String catchType = handlers.get(label);\n    if (catchType != null) {\n      insertFrameReplaceStack(label, Type.getObjectType(catchType));\n      onCatch(catchType);\n    }\n  }\n\n  @Override\n  public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {\n    if (type != null) {\n      handlers.put(handler, type);\n    }\n    super.visitTryCatchBlock(start, end, handler, type);\n  }\n\n  protected void onCatch(String type) {\n    asm.println(\"catching \" + type);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ClassCache.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport java.lang.ref.PhantomReference;\nimport java.lang.ref.ReferenceQueue;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.concurrent.ConcurrentMap;\nimport org.jctools.maps.NonBlockingHashMap;\nimport org.jctools.maps.NonBlockingIdentityHashMap;\nimport org.openjdk.btrace.instr.ClassInfo.ClassName;\n\n/**\n * A simple class cache holding {@linkplain ClassInfo} instances and being searchable either by\n * {@linkplain Class} or a tuple of {@code (className, classLoader)}\n *\n * @author Jaroslav Bachorik\n */\npublic final class ClassCache {\n  private static final class CacheKey {\n    public final String name;\n    public final int id;\n\n    private final int hashCode;\n\n    public CacheKey(String name, int id) {\n      this.name = name;\n      this.id = id;\n      this.hashCode = Objects.hash(name, id);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n      if (this == o) return true;\n      if (o == null || getClass() != o.getClass()) return false;\n      CacheKey cacheKey = (CacheKey) o;\n      return id == cacheKey.id && name.equals(cacheKey.name);\n    }\n\n    @Override\n    public int hashCode() {\n      return hashCode;\n    }\n  }\n\n  private static final class ClassLoaderReference extends PhantomReference<ClassLoader> {\n    final CacheKey key;\n\n    public ClassLoaderReference(ClassLoader referent, ReferenceQueue<? super ClassLoader> q) {\n      super(referent, q);\n      this.key = getCacheKey(referent);\n    }\n  }\n\n  private final Map<ClassLoaderReference, ClassLoaderReference> loaderRefs =\n      new NonBlockingIdentityHashMap<>();\n  private final ReferenceQueue<ClassLoader> cleanupQueue = new ReferenceQueue<>();\n  private final ConcurrentMap<CacheKey, ConcurrentMap<ClassName, ClassInfo>> cacheMap =\n      new NonBlockingHashMap<>();\n  private final ConcurrentMap<ClassName, ClassInfo> bootstrapInfos = new NonBlockingHashMap<>(500);\n\n  private final Timer cleanupTimer = new Timer(true);\n\n  public static ClassCache getInstance() {\n    return Singleton.INSTANCE;\n  }\n\n  ClassCache(long cleanupPeriod) {\n    cleanupTimer.schedule(\n        new TimerTask() {\n          @Override\n          public void run() {\n            ClassLoaderReference ref = null;\n            while ((ref = (ClassLoaderReference) cleanupQueue.poll()) != null) {\n              cacheMap.remove(ref.key);\n              loaderRefs.remove(ref);\n            }\n          }\n        },\n        cleanupPeriod,\n        cleanupPeriod);\n  }\n\n  public ClassInfo get(Class<?> clz) {\n    return get(clz.getClassLoader(), clz.getName());\n  }\n\n  /**\n   * Returns a cached {@linkplain ClassInfo} value. If the corresponding value has not been cached\n   * yet then it is created and put into the cache.\n   *\n   * @param cl The associated {@linkplain ClassLoader}\n   * @param className The Java class name or internal class name\n   */\n  public ClassInfo get(ClassLoader cl, String className) {\n    return get(cl, new ClassName(className));\n  }\n\n  ClassInfo get(ClassLoader cl, ClassName className) {\n    ConcurrentMap<ClassName, ClassInfo> infos = getInfos(cl);\n\n    return infos.computeIfAbsent(className, k -> new ClassInfo(ClassCache.this, cl, k));\n  }\n\n  ConcurrentMap<ClassName, ClassInfo> getInfos(ClassLoader cl) {\n    if (cl == null) {\n      return bootstrapInfos;\n    }\n    boolean[] rslt = new boolean[] {false};\n    ConcurrentMap<ClassName, ClassInfo> infos =\n        cacheMap.computeIfAbsent(\n            getCacheKey(cl),\n            k -> {\n              rslt[0] = true;\n              return new NonBlockingHashMap<>(500);\n            });\n    if (rslt[0]) {\n      ClassLoaderReference ref = new ClassLoaderReference(cl, cleanupQueue);\n      loaderRefs.put(ref, ref);\n    }\n    return infos;\n  }\n\n  private static CacheKey getCacheKey(ClassLoader cl) {\n    return new CacheKey(cl.getClass().getName(), System.identityHashCode(cl));\n  }\n\n  int getSize() {\n    return cacheMap.size();\n  }\n\n  private static final class Singleton {\n    private static final ClassCache INSTANCE = new ClassCache(5000);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ClassFilter.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.AnnotationVisitor;\nimport org.objectweb.asm.Attribute;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.FieldVisitor;\nimport org.objectweb.asm.MethodVisitor;\nimport org.openjdk.btrace.core.PrefixMap;\nimport org.openjdk.btrace.core.annotations.BTrace;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.ref.Reference;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Pattern;\nimport java.util.regex.PatternSyntaxException;\n\n/**\n * This class checks whether a given target class matches at least one probe specified in a BTrace\n * class.\n *\n * @author A. Sundararajan\n */\npublic class ClassFilter {\n  private static final Class<?> REFERENCE_CLASS = Reference.class;\n  private static final PrefixMap SENSITIVE_CLASSES = new PrefixMap();\n  // Method-level sensitive filter: internalClassName -> set of \"name+desc\" signatures\n  private static final Map<String, Set<String>> SENSITIVE_METHODS = new HashMap<>();\n\n  static {\n    ClassReader.class.getClassLoader();\n    AnnotationVisitor.class.getClassLoader();\n    FieldVisitor.class.getClassLoader();\n    MethodVisitor.class.getClassLoader();\n    Attribute.class.getClassLoader();\n\n    SENSITIVE_CLASSES.add(\"java/lang/Integer\");\n    SENSITIVE_CLASSES.add(\"java/lang/Number\");\n    SENSITIVE_CLASSES.add(\"java/lang/Object\");\n    SENSITIVE_CLASSES.add(\"java/lang/String\");\n    SENSITIVE_CLASSES.add(\"java/lang/StringUTF16\");\n    SENSITIVE_CLASSES.add(\"java/lang/ThreadLocal\");\n    SENSITIVE_CLASSES.add(\"java/lang/ThreadLocal$ThreadLocalMap\");\n    SENSITIVE_CLASSES.add(\"java/lang/WeakPairMap\");\n    SENSITIVE_CLASSES.add(\"java/lang/WeakPairMap$Pair$Weak\");\n    SENSITIVE_CLASSES.add(\"java/lang/instrument/\");\n    SENSITIVE_CLASSES.add(\"java/lang/invoke/\");\n    SENSITIVE_CLASSES.add(\"java/lang/ref/\");\n    SENSITIVE_CLASSES.add(\"java/util/concurrent/locks/LockSupport\");\n    SENSITIVE_CLASSES.add(\"java/util/concurrent/locks/AbstractQueuedSynchronizer\");\n    SENSITIVE_CLASSES.add(\"java/util/concurrent/locks/AbstractQueuedSynchronizer$ExclusiveNode\");\n    SENSITIVE_CLASSES.add(\"java/util/concurrent/locks/AbstractQueuedSynchronizer$Node\");\n    SENSITIVE_CLASSES.add(\"java/util/concurrent/locks/AbstractOwnableSynchronizer\");\n    SENSITIVE_CLASSES.add(\"java/util/concurrent/locks/ReentrantLock\");\n    SENSITIVE_CLASSES.add(\"java/util/concurrent/ConcurrentHashMap\");\n\n    SENSITIVE_CLASSES.add(\"jdk/internal/\");\n    SENSITIVE_CLASSES.add(\"sun/invoke/\");\n    SENSITIVE_CLASSES.add(\"sun/reflect/\");\n    SENSITIVE_CLASSES.add(\"org/openjdk/btrace/\");\n\n    // Method-level exclusions for Thread: ThreadLocal accessor/mutator methods create infinite\n    // recursion on JDK 25+ where ThreadLocal.createMap calls Thread.setThreadLocals.\n    addSensitiveMethod(\"java/lang/Thread\", \"threadLocals\");\n    addSensitiveMethod(\"java/lang/Thread\", \"setThreadLocals\");\n    addSensitiveMethod(\"java/lang/Thread\", \"terminatingThreadLocals\");\n    addSensitiveMethod(\"java/lang/Thread\", \"setTerminatingThreadLocals\");\n  }\n\n  private final List<OnMethod> onMethods;\n  private Set<String> sourceClasses;\n  private Pattern[] sourceClassPatterns;\n  private String[] annotationClasses;\n  private Pattern[] annotationClassPatterns;\n  // +foo type class pattern in any @OnMethod.\n  private String[] superTypes;\n  // same as above but stored in internal name form ('/' instead of '.')\n  private String[] superTypesInternal;\n\n  public ClassFilter(Iterable<OnMethod> onMethods) {\n    this.onMethods = new ArrayList<>();\n    for (OnMethod om : onMethods) {\n      this.onMethods.add(om);\n    }\n    init();\n  }\n\n  /*\n   * return whether given Class is subtype of given type name\n   * Note that we can not use Class.isAssignableFrom because the other\n   * type is specified by just name and not by Class object.\n   */\n  public static boolean isSubTypeOf(Class<?> clazz, String typeName) {\n    if (clazz == null) {\n      return false;\n    } else if (clazz.getName().equals(typeName)) {\n      return true;\n    } else {\n      for (Class<?> iface : clazz.getInterfaces()) {\n        if (isSubTypeOf(iface, typeName)) {\n          return true;\n        }\n      }\n      return isSubTypeOf(clazz.getSuperclass(), typeName);\n    }\n  }\n\n  /**\n   * Return whether given Class <i>typeA</i> is subtype of any of the given type names.\n   *\n   * @param typeA the type to check\n   * @param loader the classloader for loading the type (my be null)\n   * @param types any requested supertypes\n   */\n  public static boolean isSubTypeOf(String typeA, ClassLoader loader, String... types) {\n    if (typeA == null || typeA.equals(Constants.OBJECT_INTERNAL)) {\n      return false;\n    }\n    if (types.length == 0) {\n      return false;\n    }\n\n    boolean internal = types[0].contains(\"/\");\n\n    loader = (loader != null ? loader : ClassLoader.getSystemClassLoader());\n\n    if (internal) {\n      typeA = typeA.replace('.', '/');\n    } else {\n      typeA = typeA.replace('/', '.');\n    }\n\n    Set<String> typeSet = new HashSet<>(Arrays.asList(types));\n    if (typeSet.contains(typeA)) {\n      return true;\n    }\n    ClassInfo ci = ClassCache.getInstance().get(loader, typeA);\n    Collection<ClassInfo> sTypesInfo = ci.getSupertypes(false);\n    if (sTypesInfo != null) {\n      Collection<String> sTypes = new ArrayList<>(sTypesInfo.size());\n      for (ClassInfo sCi : sTypesInfo) {\n        sTypes.add(internal ? sCi.getClassName() : sCi.getJavaClassName());\n      }\n      sTypes.retainAll(typeSet);\n      return !sTypes.isEmpty();\n    } else {\n      return false;\n    }\n  }\n\n  /*\n   * Certain classes like java.lang.ThreadLocal and it's\n   * inner classes, java.lang.Object cannot be safely\n   * instrumented with BTrace. This is because BTrace uses\n   * ThreadLocal class to check recursive entries due to\n   * BTrace's own functions. But this leads to infinite recursions\n   * if BTrace instruments java.lang.ThreadLocal for example.\n   * For now, we avoid such classes till we find a solution.\n   */\n  public static boolean isSensitiveClass(String name) {\n    return SENSITIVE_CLASSES.contains(name);\n  }\n\n  public static boolean isSensitiveMethod(String owner, String name, String desc) {\n    Set<String> methods = SENSITIVE_METHODS.get(owner);\n    return methods != null && !methods.isEmpty() && methods.contains(name);\n  }\n\n  private static void addSensitiveMethod(String owner, String name) {\n    SENSITIVE_METHODS.computeIfAbsent(owner, k -> new HashSet<>()).add(name);\n  }\n\n  public boolean isCandidate(Class<?> target) {\n    if (target.isInterface() || target.isPrimitive() || target.isArray()) {\n      return false;\n    }\n\n    if (REFERENCE_CLASS.equals(target)) {\n      // instrumenting the <b>java.lang.ref.Reference</b> class will lead\n      // to StackOverflowError in <b>java.lang.ThreadLocal.get()</b>\n      return false;\n    }\n\n    try {\n      // ignore classes annotated with @BTrace -\n      // We don't want to instrument tracing classes!\n      if (target.getAnnotation(BTrace.class) != null) {\n        return false;\n      }\n    } catch (Throwable t) {\n      // thrown from java.lang.Class.initAnnotationsIfNecessary()\n      // seems to be a case when trying to access non-existing annotations\n      // on a superclass\n      // * messed up situation - ignore the class *\n      return false;\n    }\n\n    String className = target.getName();\n    if (isNameMatching(className)) {\n      return true;\n    }\n\n    for (Pattern pat : sourceClassPatterns) {\n      if (pat.matcher(className).matches()) {\n        return true;\n      }\n    }\n\n    for (String st : superTypes) {\n      if (isSubTypeOf(target, st)) {\n        return true;\n      }\n    }\n\n    Annotation[] annotations = target.getAnnotations();\n    String[] annoTypes = new String[annotations.length];\n    for (int i = 0; i < annotations.length; i++) {\n      annoTypes[i] = annotations[i].annotationType().getName();\n    }\n\n    for (String name : annotationClasses) {\n      for (String annoType : annoTypes) {\n        if (name.equals(annoType)) {\n          return true;\n        }\n      }\n    }\n\n    for (Pattern pat : annotationClassPatterns) {\n      for (String annoType : annoTypes) {\n        if (pat.matcher(annoType).matches()) {\n          return true;\n        }\n      }\n    }\n\n    return false;\n  }\n\n  public boolean isNameMatching(String clzName) {\n    if (sourceClasses.contains(clzName)) {\n      return true;\n    }\n\n    for (Pattern pat : sourceClassPatterns) {\n      if (pat.matcher(clzName).matches()) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private void init() {\n    List<String> strSrcList = new ArrayList<>();\n    List<Pattern> patSrcList = new ArrayList<>();\n    List<String> superTypesList = new ArrayList<>();\n    List<String> superTypesInternalList = new ArrayList<>();\n    List<String> strAnoList = new ArrayList<>();\n    List<Pattern> patAnoList = new ArrayList<>();\n\n    for (OnMethod om : onMethods) {\n      String className = om.getClazz();\n      if (className.length() == 0) {\n        continue;\n      }\n      if (om.isClassRegexMatcher()) {\n        try {\n          Pattern p = Pattern.compile(className);\n          if (om.isClassAnnotationMatcher()) {\n            patAnoList.add(p);\n          } else {\n            patSrcList.add(p);\n          }\n        } catch (PatternSyntaxException pse) {\n          System.err.println(\n              \"btrace ERROR: invalid regex pattern - \"\n                  + className.substring(1, className.length() - 1));\n        }\n      } else if (om.isClassAnnotationMatcher()) {\n        strAnoList.add(className);\n      } else if (om.isSubtypeMatcher()) {\n        superTypesList.add(className);\n        superTypesInternalList.add(className.replace('.', '/'));\n      } else {\n        strSrcList.add(className);\n      }\n    }\n\n    sourceClasses = new HashSet<>(strSrcList.size());\n    sourceClasses.addAll(strSrcList);\n    sourceClassPatterns = new Pattern[patSrcList.size()];\n    patSrcList.toArray(sourceClassPatterns);\n    superTypes = new String[superTypesList.size()];\n    superTypesList.toArray(superTypes);\n    superTypesInternal = new String[superTypesInternalList.size()];\n    superTypesInternalList.toArray(superTypesInternal);\n    annotationClasses = new String[strAnoList.size()];\n    strAnoList.toArray(annotationClasses);\n    annotationClassPatterns = new Pattern[patAnoList.size()];\n    patAnoList.toArray(annotationClassPatterns);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ClassInfo.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.LinkedHashSet;\nimport java.util.Objects;\nimport java.util.Set;\n\n/**\n * Arbitrary class info type allowing access to supertype information also for not-already-loaded\n * classes.\n *\n * @author Jaroslav Bachorik\n */\npublic final class ClassInfo {\n  private static final Logger log = LoggerFactory.getLogger(ClassInfo.class);\n\n  private static final ClassLoader SYS_CL = ClassLoader.getSystemClassLoader();\n  private static volatile MethodHandle BSTRP_CHECK_MTD;\n  private final String cLoaderId;\n  private final ClassName classId;\n\n  // @ThreadSafe\n  private final Collection<ClassInfo> supertypes = new ArrayList<>();\n  private final ClassCache cache;\n  private boolean isInterface = false;\n  private boolean isAvailable = false;\n\n  ClassInfo(ClassCache cache, Class<?> clz) {\n    this.cache = cache;\n    ClassLoader cl = clz.getClassLoader();\n    cLoaderId = (cl != null ? cl.toString() : \"<null>\");\n    classId = new ClassName(clz.getName());\n    Class<?> supr = clz.getSuperclass();\n    if (supr != null) {\n      supertypes.add(cache.get(supr));\n    }\n    for (Class<?> itfc : clz.getInterfaces()) {\n      if (itfc != null) {\n        supertypes.add(cache.get(itfc));\n      }\n    }\n    isInterface = clz.isInterface();\n    isAvailable = true;\n  }\n\n  ClassInfo(ClassCache cache, ClassLoader cl, ClassName cName) {\n    this.cache = cache;\n    cLoaderId = (cl != null ? cl.toString() : \"<null>\");\n    classId = cName;\n    loadExternalClass(cl, cName);\n  }\n\n  private static ClassLoader inferClassLoader(ClassLoader initiating, ClassName className) {\n    if (className == null) {\n      return initiating;\n    }\n\n    String jClassName = className.getJavaClassName().toString();\n    if (initiating == null || isBootstrap(jClassName)) {\n      return null;\n    } else {\n      String rsrcName = className.getResourcePath();\n      ClassLoader cl = initiating;\n      ClassLoader prev = initiating;\n      while (cl != null) {\n        try {\n          if (cl.getResource(rsrcName) == null) {\n            return prev;\n          }\n        } catch (Throwable t) {\n          // some containers can impose additional restrictions on loading resources and error on\n          // unexpected state\n          log.warn(\"Failed to get resource {}\", rsrcName, t);\n        }\n        prev = cl;\n        cl = cl.getParent();\n      }\n      return initiating;\n    }\n  }\n\n  // package private only for testing purposes\n  static boolean isBootstrap(String className) {\n    return BTraceRuntime.isBootstrapClass(className);\n  }\n\n  /**\n   * Retrieves supertypes (including interfaces)\n   *\n   * @param onlyDirect only immediate supertype and implemented interfaces\n   * @return supertypes (including interfaces)\n   */\n  public Collection<ClassInfo> getSupertypes(boolean onlyDirect) {\n    if (onlyDirect) {\n      return supertypes;\n    }\n    Set<ClassInfo> supers = new LinkedHashSet<>(supertypes);\n    for (ClassInfo ci : supertypes) {\n      supers.addAll(ci.getSupertypes(onlyDirect));\n    }\n    return supers;\n  }\n\n  /**\n   * Associated class loader string representation as returned by {@code cl.toString()} or {@code\n   * \"<null>\"}\n   *\n   * @return associated class loader id\n   */\n  public String getLoaderId() {\n    return cLoaderId;\n  }\n\n  /**\n   * Class ID = internal class name\n   *\n   * @return internal class name\n   */\n  public String getClassName() {\n    return classId.getInternalClassName().toString();\n  }\n\n  public String getJavaClassName() {\n    return classId.getJavaClassName().toString();\n  }\n\n  public boolean isInterface() {\n    return isInterface;\n  }\n\n  public boolean isAvailable() {\n    return isAvailable;\n  }\n\n  // not thread safe - must be called only from the constructor\n  private void loadExternalClass(ClassLoader cl, ClassName className) {\n    String resourcePath = className.getResourcePath();\n\n    try {\n      InputStream typeIs =\n          cl == null\n              ? SYS_CL.getResourceAsStream(resourcePath)\n              : cl.getResourceAsStream(resourcePath);\n      if (typeIs != null) {\n        try {\n          BTraceClassReader cr = new BTraceClassReader(cl, typeIs);\n\n          isInterface = cr.isInterface();\n          String[] info = cr.readClassSupers();\n          String superName = info[0];\n          if (superName != null) {\n            ClassName superClassName = new ClassName(superName);\n            supertypes.add(cache.get(inferClassLoader(cl, superClassName), superClassName));\n          }\n          if (info.length > 1) {\n            for (int i = 1; i < info.length; i++) {\n              String ifc = info[i];\n              if (ifc != null) {\n                ClassName ifcClassName = new ClassName(ifc);\n                supertypes.add(cache.get(inferClassLoader(cl, ifcClassName), ifcClassName));\n              }\n            }\n          }\n          isAvailable = true;\n        } catch (IllegalArgumentException | IOException e) {\n          log.warn(\"Unable to load class: {}\", className, e);\n        }\n      }\n    } catch (Throwable t) {\n      // some containers can impose additional restrictions on classloaders throwing exceptions when\n      // not in expected state\n      log.warn(\"Failed to load class {}\", className, t);\n    }\n  }\n\n  @Override\n  public int hashCode() {\n    int hash = 5;\n    hash = 37 * hash + Objects.hashCode(cLoaderId);\n    hash = 37 * hash + Objects.hashCode(classId);\n    return hash;\n  }\n\n  @Override\n  public boolean equals(Object obj) {\n    if (this == obj) {\n      return true;\n    }\n    if (obj == null) {\n      return false;\n    }\n    if (getClass() != obj.getClass()) {\n      return false;\n    }\n    ClassInfo other = (ClassInfo) obj;\n    if (!Objects.equals(cLoaderId, other.cLoaderId)) {\n      return false;\n    }\n    return Objects.equals(classId, other.classId);\n  }\n\n  @Override\n  public String toString() {\n    return \"ClassInfo{\"\n        + \"cLoaderId=\"\n        + cLoaderId\n        + \", classId=\"\n        + classId\n        + \", supertypes=\"\n        + supertypes\n        + '}';\n  }\n\n  private abstract static class BaseClassName implements CharSequence {\n    protected final CharSequence wrapped;\n    private String str = null;\n\n    protected BaseClassName(CharSequence wrapped) {\n      this.wrapped = wrapped;\n    }\n\n    @Override\n    public int length() {\n      return wrapped.length();\n    }\n\n    @Override\n    public CharSequence subSequence(int start, int end) {\n      throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String toString() {\n      if (str == null) {\n        char[] val = new char[wrapped.length()];\n        for (int i = 0; i < wrapped.length(); i++) {\n          val[i] = charAt(i);\n        }\n        str = new String(val);\n      }\n      return str;\n    }\n  }\n\n  private static final class JavaClassName extends BaseClassName {\n    public JavaClassName(CharSequence wrapped) {\n      super(wrapped);\n    }\n\n    @Override\n    public char charAt(int index) {\n      char c = wrapped.charAt(index);\n      return (c == '/' ? '.' : c);\n    }\n  }\n\n  private static final class InternalClassName extends BaseClassName {\n    public InternalClassName(CharSequence wrapped) {\n      super(wrapped);\n    }\n\n    @Override\n    public char charAt(int index) {\n      char c = wrapped.charAt(index);\n      return (c == '.' ? '/' : c);\n    }\n  }\n\n  static final class ClassName {\n    private final CharSequence cName;\n    private final JavaClassName jcName;\n    private final InternalClassName icName;\n    private String rsrcName = null;\n\n    public ClassName(CharSequence cName) {\n      this.cName = cName;\n      jcName = new JavaClassName(cName);\n      icName = new InternalClassName(cName);\n    }\n\n    public CharSequence getJavaClassName() {\n      return jcName;\n    }\n\n    public CharSequence getInternalClassName() {\n      return icName;\n    }\n\n    public String getResourcePath() {\n      if (rsrcName == null) {\n        rsrcName = icName + \".class\";\n      }\n      return rsrcName;\n    }\n\n    @Override\n    public String toString() {\n      return String.valueOf(cName);\n    }\n\n    @Override\n    public int hashCode() {\n      int h = 7;\n      int len = cName.length();\n      for (int i = 0; i < len; i++) {\n        char c = cName.charAt(i);\n        h = 31 * h + (c == '.' ? '/' : c);\n      }\n\n      return h;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n      if (this == obj) {\n        return true;\n      }\n      if (obj == null) {\n        return false;\n      }\n      if (getClass() != obj.getClass()) {\n        return false;\n      }\n      ClassName other = (ClassName) obj;\n      if (cName.length() != other.cName.length()) {\n        return false;\n      }\n      for (int i = 0; i < cName.length(); i++) {\n        char c1 = cName.charAt(i);\n        char c2 = other.cName.charAt(i);\n        switch (c1) {\n          case '.':\n          case '/':\n            {\n              if (c2 != '.' && c2 != '/') {\n                return false;\n              }\n              break;\n            }\n          default:\n            {\n              if (c1 != c2) {\n                return false;\n              }\n            }\n        }\n      }\n      return true;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/Constants.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport java.util.regex.Pattern;\nimport org.objectweb.asm.Type;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Injected;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnError;\nimport org.openjdk.btrace.core.annotations.OnEvent;\nimport org.openjdk.btrace.core.annotations.OnExit;\nimport org.openjdk.btrace.core.annotations.OnLowMemory;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.OnProbe;\nimport org.openjdk.btrace.core.annotations.OnTimer;\nimport org.openjdk.btrace.core.annotations.PeriodicEvent;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.extensions.Extension;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\nimport org.openjdk.btrace.runtime.LinkingFlag;\n\n/**\n * Constants shared by few classes.\n *\n * @author A. Sundararajan\n */\npublic abstract class Constants {\n  public static final String BTRACE_METHOD_PREFIX = \"$btrace$\";\n\n  public static final String CONSTRUCTOR = \"<init>\";\n  public static final String CLASS_INITIALIZER = \"<clinit>\";\n\n  public static final Type NULL_TYPE = Type.getType(\"L$$null\");\n  public static final Type TOP_TYPE = Type.getType(\"L$$top\");\n\n  public static final Type VOIDREF_TYPE = Type.getType(\"Ljava/lang/Void;\");\n\n  public static final String OBJECT_INTERNAL = \"java/lang/Object\";\n  public static final String OBJECT_DESC = \"L\" + OBJECT_INTERNAL + \";\";\n  public static final Type OBJECT_TYPE = Type.getType(OBJECT_DESC);\n\n  public static final String ANYTYPE_INTERNAL = \"org/openjdk/btrace/core/types/AnyType\";\n  public static final String ANYTYPE_DESC = \"L\" + ANYTYPE_INTERNAL + \";\";\n  public static final Type ANYTYPE_TYPE = Type.getType(ANYTYPE_DESC);\n\n  public static final String CLASS_DESC = \"Ljava/lang/Class;\";\n  public static final Type CLASS_TYPE = Type.getType(CLASS_DESC);\n\n  public static final String STRING_INTERNAL = \"java/lang/String\";\n  public static final String STRING_DESC = \"L\" + STRING_INTERNAL + \";\";\n  public static final Type STRING_TYPE = Type.getType(STRING_DESC);\n\n  public static final String STRING_BUILDER_INTERNAL = \"java/lang/StringBuilder\";\n  public static final String STRING_BUILDER_DESC = \"L\" + STRING_BUILDER_INTERNAL + \";\";\n  public static final Type STRING_BUILDER_TYPE = Type.getType(STRING_BUILDER_DESC);\n\n  public static final String VOID_DESC = \"V\";\n  public static final String BOOLEAN_DESC = \"Z\";\n  public static final String INT_DESC = \"I\";\n\n  public static final String THROWABLE_INTERNAL = \"java/lang/Throwable\";\n  public static final String THROWABLE_DESC = \"L\" + THROWABLE_INTERNAL + \";\";\n  public static final Type THROWABLE_TYPE = Type.getType(THROWABLE_DESC);\n\n  public static final String BTRACERTACCESS_INTERNAL =\n      \"org/openjdk/btrace/runtime/BTraceRuntimeAccess\";\n  public static final String BTRACERTACCESS_DESC = \"L\" + BTRACERTACCESS_INTERNAL + \";\";\n  public static final String BTRACERT_INTERNAL = \"org/openjdk/btrace/core/BTraceRuntime\";\n  public static final String BTRACERT_DESC = \"L\" + BTRACERT_INTERNAL + \";\";\n  public static final String BTRACERTIMPL_INTERNAL = \"org/openjdk/btrace/core/BTraceRuntime$Impl\";\n  public static final String BTRACERTIMPL_DESC = \"L\" + BTRACERTIMPL_INTERNAL + \";\";\n  public static final String BTRACERTBRIDGE_INTERNAL =\n      \"org/openjdk/btrace/core/BTraceRuntimeBridge\";\n  public static final String BTRACERTBRIDGE_DESC = \"L\" + BTRACERTBRIDGE_INTERNAL + \";\";\n  public static final Type BTRACERT_TYPE = Type.getType(BTRACERT_DESC);\n\n  public static final String THREAD_LOCAL_INTERNAL = \"java/lang/ThreadLocal\";\n  public static final String THREAD_LOCAL_DESC = \"L\" + THREAD_LOCAL_INTERNAL + \";\";\n  public static final Type THREAD_LOCAL_TYPE = Type.getType(ThreadLocal.class);\n\n  public static final Type LINKING_FLAG_TYPE = Type.getType(LinkingFlag.class);\n  public static final String LINKING_FLAG_INTERNAL = LINKING_FLAG_TYPE.getInternalName();\n\n  // BTrace specific stuff\n  public static final String BTRACE_UTILS = Type.getInternalName(BTraceUtils.class);\n\n  public static final String EXTENSION = Type.getInternalName(Extension.class);\n\n  public static final String EXTENSION_DESC = Type.getDescriptor(Extension.class);\n\n  public static final String BTRACE_DESC = Type.getDescriptor(BTrace.class);\n\n  public static final String ONMETHOD_DESC = Type.getDescriptor(OnMethod.class);\n\n  public static final String JFRPERIODIC_DESC = Type.getDescriptor(PeriodicEvent.class);\n\n  public static final String JFREVENTFACTORY_DESC = Type.getDescriptor(JfrEvent.Factory.class);\n\n  public static final String BTRACE_PROBECLASSNAME_DESC = Type.getDescriptor(ProbeClassName.class);\n\n  public static final String BTRACE_PROBEMETHODNAME_DESC =\n      Type.getDescriptor(ProbeMethodName.class);\n\n  public static final String ONTIMER_DESC = Type.getDescriptor(OnTimer.class);\n  public static final String ONEVENT_DESC = Type.getDescriptor(OnEvent.class);\n  public static final String ONEXIT_DESC = Type.getDescriptor(OnExit.class);\n  public static final String ONERROR_DESC = Type.getDescriptor(OnError.class);\n  public static final String ONLOWMEMORY_DESC = Type.getDescriptor(OnLowMemory.class);\n\n  public static final String SAMPLED_DESC = Type.getDescriptor(Sampled.class);\n\n  public static final String SAMPLER_DESC = Type.getDescriptor(Sampled.Sampler.class);\n\n  public static final String ONPROBE_DESC = Type.getDescriptor(OnProbe.class);\n\n  public static final String LOCATION_DESC = Type.getDescriptor(Location.class);\n\n  public static final String LEVEL_DESC = Type.getDescriptor(Level.class);\n\n  public static final String WHERE_DESC = Type.getDescriptor(Where.class);\n\n  public static final String KIND_DESC = Type.getDescriptor(Kind.class);\n\n  public static final String INJECTED_DESC = Type.getDescriptor(Injected.class);\n\n  // RequestPermission annotations removed; permissions are managed via descriptors and manifest.\n\n  public static final String RETURN_DESC = Type.getDescriptor(Return.class);\n\n  public static final String SELF_DESC = Type.getDescriptor(Self.class);\n\n  public static final String TARGETMETHOD_DESC = Type.getDescriptor(TargetMethodOrField.class);\n\n  public static final String TARGETINSTANCE_DESC = Type.getDescriptor(TargetInstance.class);\n\n  public static final String DURATION_DESC = Type.getDescriptor(Duration.class);\n\n  public static final String ARGSMAP_DESC = Type.getDescriptor(ArgsMap.class);\n\n  // class name pattern is specified with this pattern\n  public static final Pattern REGEX_SPECIFIER = Pattern.compile(\"/.+/\");\n\n  public static final String JAVA_LANG_THREAD_LOCAL = Type.getInternalName(ThreadLocal.class);\n  public static final String JAVA_LANG_THREAD_LOCAL_GET = \"get\";\n  public static final String JAVA_LANG_THREAD_LOCAL_GET_DESC = \"()Ljava/lang/Object;\";\n  public static final String JAVA_LANG_THREAD_LOCAL_SET = \"set\";\n  public static final String JAVA_LANG_THREAD_LOCAL_SET_DESC = \"(Ljava/lang/Object;)V\";\n\n  public static final String NUMBER_INTERNAL = \"java/lang/Number\";\n  public static final String INTEGER_BOXED_INTERNAL = \"java/lang/Integer\";\n  public static final String INTEGER_BOXED_DESC = \"L\" + INTEGER_BOXED_INTERNAL + \";\";\n  public static final String SHORT_BOXED_INTERNAL = \"java/lang/Short\";\n  public static final String SHORT_BOXED_DESC = \"L\" + SHORT_BOXED_INTERNAL + \";\";\n  public static final String LONG_BOXED_INTERNAL = \"java/lang/Long\";\n  public static final String LONG_BOXED_DESC = \"L\" + LONG_BOXED_INTERNAL + \";\";\n  public static final String FLOAT_BOXED_INTERNAL = \"java/lang/Float\";\n  public static final String FLOAT_BOXED_DESC = \"L\" + FLOAT_BOXED_INTERNAL + \";\";\n  public static final String DOUBLE_BOXED_INTERNAL = \"java/lang/Double\";\n  public static final String DOUBLE_BOXED_DESC = \"L\" + DOUBLE_BOXED_INTERNAL + \";\";\n  public static final String BYTE_BOXED_INTERNAL = \"java/lang/Byte\";\n  public static final String BYTE_BOXED_DESC = \"L\" + BYTE_BOXED_INTERNAL + \";\";\n  public static final String BOOLEAN_BOXED_INTERNAL = \"java/lang/Boolean\";\n  public static final String BOOLEAN_BOXED_DESC = \"L\" + BOOLEAN_BOXED_INTERNAL + \";\";\n  public static final String CHARACTER_BOXED_INTERNAL = \"java/lang/Character\";\n  public static final String CHARACTER_BOXED_DESC = \"L\" + CHARACTER_BOXED_INTERNAL + \";\";\n\n  public static final String BOX_VALUEOF = \"valueOf\";\n  public static final String BOX_BOOLEAN_DESC = \"(\" + BOOLEAN_DESC + \")\" + BOOLEAN_BOXED_DESC;\n  public static final String BOX_CHARACTER_DESC = \"(C)Ljava/lang/Character;\";\n  public static final String BOX_BYTE_DESC = \"(B)Ljava/lang/Byte;\";\n  public static final String BOX_SHORT_DESC = \"(S)Ljava/lang/Short;\";\n  public static final String BOX_INTEGER_DESC = \"(I)Ljava/lang/Integer;\";\n  public static final String BOX_LONG_DESC = \"(J)Ljava/lang/Long;\";\n  public static final String BOX_FLOAT_DESC = \"(F)Ljava/lang/Float;\";\n  public static final String BOX_DOUBLE_DESC = \"(D)Ljava/lang/Double;\";\n\n  public static final String BOOLEAN_VALUE = \"booleanValue\";\n  public static final String CHAR_VALUE = \"charValue\";\n  public static final String BYTE_VALUE = \"byteValue\";\n  public static final String SHORT_VALUE = \"shortValue\";\n  public static final String INT_VALUE = \"intValue\";\n  public static final String LONG_VALUE = \"longValue\";\n  public static final String FLOAT_VALUE = \"floatValue\";\n  public static final String DOUBLE_VALUE = \"doubleValue\";\n\n  public static final String BOOLEAN_VALUE_DESC = \"()Z\";\n  public static final String CHAR_VALUE_DESC = \"()C\";\n  public static final String BYTE_VALUE_DESC = \"()B\";\n  public static final String SHORT_VALUE_DESC = \"()S\";\n  public static final String INT_VALUE_DESC = \"()I\";\n  public static final String LONG_VALUE_DESC = \"()J\";\n  public static final String FLOAT_VALUE_DESC = \"()F\";\n  public static final String DOUBLE_VALUE_DESC = \"()D\";\n  public static final String EMBEDDED_BTRACE_SECTION_HEADER = \"META-INF/btrace/\";\n\n  public static final String BTRACE_LEVEL_FLD = \"$btrace$$level\";\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ErrorReturnInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.ATHROW;\nimport static org.openjdk.btrace.instr.Constants.THROWABLE_INTERNAL;\nimport static org.openjdk.btrace.instr.Constants.THROWABLE_TYPE;\n\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * This visitor helps in inserting code whenever a method \"returns\" because of an exception (i.e.,\n * no exception handler in the method and so it's frame poped). The code to insert on method error\n * return may be decided by derived class. By default, this class inserts code to print message to\n * say \"no handler here\".\n *\n * @author A. Sundararajan\n */\npublic class ErrorReturnInstrumentor extends MethodReturnInstrumentor {\n  private final Label start = new Label();\n  private final Label end = new Label();\n\n  public ErrorReturnInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  protected void visitMethodPrologue() {\n    addTryCatchHandler(start, end);\n    visitLabel(start);\n    super.visitMethodPrologue();\n  }\n\n  @Override\n  public void visitMaxs(int maxStack, int maxLocals) {\n    visitTryCatchBlock(start, end, end, THROWABLE_INTERNAL);\n    visitLabel(end);\n    insertFrameReplaceStack(end, THROWABLE_TYPE);\n    onErrorReturn();\n    visitInsn(ATHROW);\n    super.visitMaxs(maxStack, maxLocals);\n  }\n\n  @Override\n  protected void onMethodEntry() {}\n\n  @Override\n  protected void onMethodReturn(int opcode) {}\n\n  protected void onErrorReturn() {\n    asm.println(\"error return from \" + getName() + getDescriptor());\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/FieldAccessInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * This visitor helps in inserting code whenever an field access is done. The code to insert on\n * field access may be decided by derived class. By default, this class inserts code to print the\n * field access.\n *\n * @author A. Sundararajan\n */\npublic class FieldAccessInstrumentor extends MethodInstrumentor {\n  protected boolean isStaticAccess = false;\n\n  public FieldAccessInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  public void visitFieldInsn(int opcode, String owner, String name, String desc) {\n    boolean get;\n    // ignore any internal BTrace fields\n    if (name.contains(\"$btrace$\")) {\n      super.visitFieldInsn(opcode, owner, name, desc);\n      return;\n    }\n\n    get = opcode == GETFIELD || opcode == GETSTATIC;\n    isStaticAccess = (opcode == GETSTATIC || opcode == PUTSTATIC);\n\n    if (get) {\n      onBeforeGetField(opcode, owner, name, desc);\n    } else {\n      onBeforePutField(opcode, owner, name, desc);\n    }\n    super.visitFieldInsn(opcode, owner, name, desc);\n    if (get) {\n      onAfterGetField(opcode, owner, name, desc);\n    } else {\n      onAfterPutField(opcode, owner, name, desc);\n    }\n  }\n\n  protected void onBeforeGetField(int opcode, String owner, String name, String desc) {}\n\n  protected void onAfterGetField(int opcode, String owner, String name, String desc) {}\n\n  protected void onBeforePutField(int opcode, String owner, String name, String desc) {}\n\n  protected void onAfterPutField(int opcode, String owner, String name, String desc) {}\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/HandlerRepositoryImpl.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport org.openjdk.btrace.core.HandlerRepository;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.runtime.IndyDispatcher;\nimport org.openjdk.btrace.runtime.Interval;\nimport org.openjdk.btrace.runtime.BTraceRuntimes;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.MethodType;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Implementation of {@link HandlerRepository} that resolves probe handler {@link MethodHandle}s\n * via {@link MethodHandles#publicLookup()}.findStatic() on the probe class.\n *\n * <p>Probe handler methods stay in the probe class (per-probe ClassLoader on JDK 8/9-14, or\n * a hidden class on JDK 15+). No bytecode copying is performed.\n *\n * <p><b>Caching:</b> only successful resolutions are cached; failures are returned as\n * {@code null} without poisoning the cache. IndyDispatcher handles transient failure by\n * installing a {@code MutableCallSite} trampoline that retries on each invocation, so a\n * negative cache is not needed — and would in fact defeat the self-healing behaviour.\n */\npublic final class HandlerRepositoryImpl {\n  private static final Logger log = LoggerFactory.getLogger(HandlerRepositoryImpl.class);\n\n  static {\n    // Wire up to IndyDispatcher (bootstrap CL) via reflection.\n    // IndyDispatcher.repository is set to a method-reference calling our resolveHandler().\n    try {\n      Class<?> dispatcherClz = Class.forName(\"org.openjdk.btrace.runtime.IndyDispatcher\");\n      HandlerRepository hook = HandlerRepositoryImpl::resolveHandler;\n      dispatcherClz.getField(\"repository\").set(null, hook);\n    } catch (Throwable t) {\n      log.warn(\"Unable to initialize BTrace IndyDispatcher support\", t);\n    }\n  }\n\n  /** Maps probe class name (internal form) → live BTraceProbe instance. */\n  private static final Map<String, BTraceProbe> probeMap = new ConcurrentHashMap<>();\n\n  /**\n   * Register a probe after its class has been defined in the JVM. Must be called before\n   * any instrumented call site targeting this probe is invoked. If invocation arrives\n   * first, {@link org.openjdk.btrace.runtime.IndyDispatcher} installs a self-relinking\n   * trampoline that will pick up the probe on its next invocation.\n   */\n  public static void registerProbe(BTraceProbe probe) {\n    String probeName = probe.getClassName(true);\n    probeMap.put(probeName, probe);\n  }\n\n  /**\n   * Unregister a probe. Also invalidates every live {@link java.lang.invoke.MutableCallSite}\n   * targeting this probe via {@link IndyDispatcher#invalidateProbe(String)}, swapping their\n   * targets to a noop so in-flight and subsequent invocations do not enter probe handler\n   * bodies after the associated {@code BTraceRuntime} state has been torn down. This is the\n   * dispatch-level equivalent of the older \"cushion\" approach, which stubbed probe method\n   * bodies via bytecode redefine on detach — both exist to keep the instrumented application\n   * from crashing when a probe is undeployed while call sites are still live.\n   *\n   * <p>The handler {@link MethodHandle} cache is per-probe (see {@link BTraceProbe#cacheHandler})\n   * so nothing to scan here — the cache dies with the probe object.\n   */\n  public static void unregisterProbe(BTraceProbe probe) {\n    String probeName = probe.getClassName(true);\n    probeMap.remove(probeName);\n    IndyDispatcher.invalidateProbe(probeName);\n  }\n\n  /**\n   * Apply level-based guard to a handler MethodHandle. If the handler has a level requirement\n   * (enableAt annotation), wraps the handler in a guard that checks if the current probe level\n   * permits execution. This allows the JIT to optimize based on the level and avoids deopt\n   * when levels change.\n   *\n   * @param handler    the resolved handler MethodHandle\n   * @param probe      the BTraceProbe instance\n   * @param simpleHandlerName the unqualified handler method name (e.g. \"onMethod\")\n   * @param handlerType the MethodType of the handler\n   * @return the handler, possibly wrapped with a level guard\n   */\n  private static MethodHandle applyLevelGuard(\n      MethodHandle handler, BTraceProbe probe, String simpleHandlerName, MethodType handlerType) {\n    // Find the OnMethod metadata for this handler\n    Level level = null;\n    for (OnMethod om : probe.onmethods()) {\n      if (om.getMethod().equals(simpleHandlerName)) {\n        level = om.getLevel();\n        if (level != null) {\n          break;\n        }\n      }\n    }\n\n    if (level == null) {\n      return handler; // No level guard needed\n    }\n\n    // Compose the handler with a level guard. The guard will:\n    // 1. Check if current instrumentation level satisfies the requirement\n    // 2. If yes, invoke the real handler\n    // 3. If no, invoke a noop that returns the default value for the type\n\n    log.debug(\"Handler {} requires level check: {}\", simpleHandlerName, level.getValue());\n\n    try {\n      // Create a test MethodHandle that checks the level requirement.\n      // It takes the same arguments as the handler but returns boolean.\n      MethodType testType = handlerType.changeReturnType(boolean.class);\n      MethodHandle levelTest = createLevelCheckMH(level, testType);\n\n      // Create a noop handler that returns default value for the return type\n      MethodHandle noop = createNoopMH(handlerType);\n\n      // Compose: if level check passes, invoke handler; otherwise noop\n      return MethodHandles.guardWithTest(levelTest, handler, noop);\n    } catch (Throwable e) {\n      log.warn(\"Failed to create level guard for handler {}\", simpleHandlerName, e);\n      return handler; // Fall back to unguarded handler on error\n    }\n  }\n\n  /**\n   * Create a MethodHandle that tests if the current instrumentation level satisfies\n   * the given level requirement. Returns true if level check passes, false otherwise.\n   */\n  private static MethodHandle createLevelCheckMH(Level level, MethodType testType) throws Throwable {\n    // Get the Interval requirement (e.g., \">=100\" → [100, MAX_VALUE])\n    Interval interval = level.getValue();\n\n    // Create a static helper method that checks: currentLevel >= a && currentLevel <= b\n    // We need to invoke this helper with the level bounds and call the level getter\n    // The tricky part: we need access to BTraceRuntime to query the current level,\n    // but we don't have it as a parameter. We must create a method that can access it.\n\n    // Use a custom MethodHandle that invokes our level-checking logic\n    MethodHandle levelChecker = createLevelCheckerMH(interval);\n\n    // Drop arguments to match testType (accept same params as handler, return boolean)\n    return MethodHandles.dropArguments(levelChecker, 0, testType.parameterArray());\n  }\n\n  /**\n   * Helper: create a MethodHandle that queries BTraceRuntime.getInstrumentationLevel()\n   * and checks if it falls within the given interval.\n   */\n  private static MethodHandle createLevelCheckerMH(Interval interval) throws Throwable {\n    int minLevel = interval.getA();\n    int maxLevel = interval.getB();\n\n    // Create a MethodHandle that returns true if currentLevel is in [minLevel, maxLevel]\n    MethodHandles.Lookup lookup = MethodHandles.lookup();\n    MethodHandle checkMH = lookup.findStatic(\n        HandlerRepositoryImpl.class,\n        \"checkLevelInRange\",\n        MethodType.methodType(boolean.class, int.class, int.class, int.class));\n\n    // Bind the interval bounds as arguments at positions 0 and 1\n    // After binding: (minLevel=bound, maxLevel=bound, currentLevel=?) -> boolean\n    MethodHandle bound = MethodHandles.insertArguments(checkMH, 0, minLevel, maxLevel);\n    // After binding: (currentLevel) -> boolean\n\n    // Compose with a getter that queries the current level\n    MethodHandle getCurrentLevelMH = lookup.findStatic(\n        BTraceRuntimes.class,\n        \"getCurrentLevel\",\n        MethodType.methodType(int.class));\n    // getCurrentLevel: () -> int\n\n    // Fold: getCurrentLevel() returns int, pass result as first arg to bound\n    // Result: () -> boolean\n    return MethodHandles.foldArguments(bound, getCurrentLevelMH);\n  }\n\n  /**\n   * Static helper invoked via MethodHandle: check if level is in [min, max] range.\n   */\n  @SuppressWarnings(\"unused\") // invoked via MethodHandle\n  private static boolean checkLevelInRange(int minLevel, int maxLevel, int currentLevel) {\n    return currentLevel >= minLevel && currentLevel <= maxLevel;\n  }\n\n  /**\n   * Create a noop MethodHandle that returns the default value for the given type.\n   */\n  private static MethodHandle createNoopMH(MethodType handlerType) throws Throwable {\n    Class<?> returnType = handlerType.returnType();\n    // Reuse shared default value logic from IndyDispatcher\n    Object defaultValue = IndyDispatcher.defaultValueFor(returnType);\n    MethodHandle noop = MethodHandles.constant(returnType, defaultValue);\n    // Drop arguments so the noop accepts the handler's parameters but ignores them\n    return MethodHandles.dropArguments(noop, 0, handlerType.parameterArray());\n  }\n\n  /**\n   * Resolve a probe handler MethodHandle. Called from IndyDispatcher.bootstrap() on first\n   * execution of each instrumented call site, and subsequently from the trampoline on\n   * every retry until resolution succeeds.\n   *\n   * @param probeName   internal class name of the probe (e.g. {@code \"com/example/MyTrace\"})\n   * @param handlerName handler method name (probe-prefixed, e.g. {@code \"MyTrace$onMethod\"})\n   * @param handlerType the MethodType of the call site\n   * @return the resolved MethodHandle, or {@code null} if resolution fails (caller must\n   *         treat null as transient and retry)\n   */\n  public static MethodHandle resolveHandler(\n      String probeName, String handlerName, MethodType handlerType) {\n    BTraceProbe probe = probeMap.get(probeName);\n    if (probe == null) {\n      // Probe not registered yet. Do not cache — IndyDispatcher's trampoline will retry.\n      log.debug(\"[INDY] probe {} not registered, probeMap.size={}\", probeName, probeMap.size());\n      return null;\n    }\n\n    MethodHandle cached = probe.getCachedHandler(handlerName, handlerType);\n    if (cached != null) {\n      log.debug(\"[INDY] cached handler {} for {}\", cached, handlerName);\n      return cached;\n    }\n\n    Class<?> probeClass = probe.getProbeClass();\n    if (probeClass == null) {\n      // defineClass has not populated probeClass yet (race with register()).\n      // Do not cache — IndyDispatcher's trampoline will retry.\n      log.debug(\"[INDY] probeClass null for {}\", probeName);\n      return null;\n    }\n\n    log.debug(\"[INDY] resolving {}.{} in {}\", probeName, handlerName, probeClass.getClassLoader());\n\n    try {\n      // Strip probe-name prefix from handler name (e.g. \"MyTrace$onMethod\" → \"onMethod\")\n      int dollarIdx = handlerName.lastIndexOf('$');\n      String simpleHandlerName =\n          dollarIdx >= 0 ? handlerName.substring(dollarIdx + 1) : handlerName;\n\n      MethodHandle mh;\n      try {\n        // Try public lookup first (works for normal, accessible classes).\n        mh = MethodHandles.publicLookup().findStatic(probeClass, simpleHandlerName, handlerType);\n      } catch (IllegalAccessException publicLookupFailed) {\n        // publicLookup has limited access across classloader boundaries. For probes defined\n        // in isolated/unnamed ClassLoaders (per-probe isolation on JDK 8/9-14, or hidden\n        // classes on JDK 15+), publicLookup cannot see the handler methods. Fall back to\n        // a reflection-based approach: get the method via getDeclaredMethod, then convert\n        // it to a MethodHandle using unreflect. This works on all JDK versions.\n        log.debug(\n            \"publicLookup denied access to {}.{}, falling back to reflection-based resolution\",\n            probeName, simpleHandlerName);\n        try {\n          // Extract parameter types from the handler MethodType.\n          Class<?>[] paramTypes = new Class<?>[handlerType.parameterCount()];\n          for (int i = 0; i < paramTypes.length; i++) {\n            paramTypes[i] = handlerType.parameterType(i);\n          }\n          java.lang.reflect.Method method =\n              probeClass.getDeclaredMethod(simpleHandlerName, paramTypes);\n          method.setAccessible(true);\n          mh = MethodHandles.lookup().unreflect(method);\n        } catch (Throwable fallbackEx) {\n          // Reflection-based approach also failed. Re-throw the original exception from\n          // publicLookup so it gets logged with proper context in the outer catch.\n          throw publicLookupFailed;\n        }\n      }\n\n      // Apply level guard if this handler has a level check\n      mh = applyLevelGuard(mh, probe, simpleHandlerName, handlerType);\n\n      probe.cacheHandler(handlerName, handlerType, mh);\n\n      if (SharedSettings.GLOBAL.isDumpClasses()) {\n        log.debug(\"BTrace INDY handler resolved: {}.{}\", probeName, simpleHandlerName);\n      }\n\n      return mh;\n    } catch (Throwable e) {\n      // Log loudly: unlike transient null-repository or unregistered-probe failures,\n      // findStatic exceptions usually mean a real problem (signature mismatch, module\n      // access). Don't cache — the trampoline will retry, but the same failure is likely\n      // to recur until the probe class/bytecode is fixed.\n      log.warn(\"Failed to resolve handler '{}' in probe '{}'\", handlerName, probeName, e);\n      return null;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/InstrPackGenerator.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport org.openjdk.btrace.compiler.PackGenerator;\nimport org.openjdk.btrace.core.SharedSettings;\n\npublic final class InstrPackGenerator implements PackGenerator {\n  @Override\n  public byte[] generateProbePack(byte[] classData) throws IOException {\n    BTraceProbeNode bpn =\n        (BTraceProbeNode) new BTraceProbeFactory(SharedSettings.GLOBAL).createProbe(classData);\n    // force bytecode verification before creating the persisted representation\n    bpn.checkVerified();\n\n    ByteArrayOutputStream bos = new ByteArrayOutputStream();\n    try (DataOutputStream dos = new DataOutputStream(bos)) {\n      BTraceProbePersisted bpp = BTraceProbePersisted.from(bpn);\n      if (!bpp.isVerified()) {\n        throw new Error();\n      }\n      bpp.write(dos);\n    }\n\n    return bos.toByteArray();\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/InstrumentUtils.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\nimport static org.openjdk.btrace.instr.TypeUtils.isAnyType;\nimport static org.openjdk.btrace.instr.TypeUtils.isPrimitive;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.ClassWriter;\nimport org.objectweb.asm.Type;\n\n/**\n * @author A. Sundararajan\n * @author J. Bachorik\n */\npublic final class InstrumentUtils {\n  private static final int CW_FLAGS = 0; // ClassWriter.COMPUTE_MAXS;\n\n  /**\n   * Collects the type hierarchy into the provided list, sorted from the actual type to root. Common\n   * superclasses may be present multiple times (eg. {@code java.lang.Object}) It will use the\n   * associated classloader to locate the class file resources.\n   *\n   * @param cl the associated classloader\n   * @param type the type to compute the hierarchy closure for (either Java or internal name format)\n   * @param closure the ordered set to store the closure in\n   * @param useInternal should internal types names be used in the closure\n   */\n  public static void collectHierarchyClosure(\n      ClassLoader cl, String type, Set<String> closure, boolean useInternal) {\n    collectHierarchyClosure(cl, type, closure, useInternal, false);\n  }\n\n  /**\n   * Collects the type hierarchy into the provided list, sorted from the actual type to root. Common\n   * superclasses may be present multiple times (eg. {@code java.lang.Object}) It will use the\n   * associated classloader to locate the class file resources.\n   *\n   * @param cl the associated classloader\n   * @param type the type to compute the hierarchy closure for (either Java or internal name format)\n   * @param closure the ordered set to store the closure in\n   * @param useInternal should internal types names be used in the closure\n   */\n  public static void collectHierarchyClosure(\n      ClassLoader cl, String type, Set<String> closure, boolean useInternal, boolean ifcs) {\n    if (type == null || type.equals(Constants.OBJECT_INTERNAL)) {\n      return;\n    }\n    ClassInfo ci = ClassCache.getInstance().get(cl, type);\n\n    Set<ClassInfo> ciSet = new LinkedHashSet<>();\n\n    // add self\n    ciSet.add(ci);\n    for (ClassInfo sci : ci.getSupertypes(false)) {\n      if ((ifcs || !sci.isInterface()) && !sci.getClassName().equals(Constants.OBJECT_INTERNAL)) {\n        ciSet.add(sci);\n      }\n    }\n\n    for (ClassInfo sci : ciSet) {\n      closure.add(useInternal ? sci.getClassName() : sci.getJavaClassName());\n    }\n  }\n\n  public static boolean isAssignable(\n      Type left, Type right, ClassLoader cl, boolean exactTypeCheck) {\n    boolean isSame = left.equals(right);\n\n    if (isSame) {\n      return true;\n    }\n\n    if (TypeUtils.isVoid(left)) {\n      return TypeUtils.isVoid(right);\n    }\n\n    if (TypeUtils.isAnyType(left)) {\n      return true;\n    }\n\n    if (exactTypeCheck) {\n      return false;\n    }\n\n    if (TypeUtils.isObject(left)) {\n      return true;\n    }\n\n    Set<String> closure = new HashSet<>();\n    collectHierarchyClosure(cl, right.getInternalName(), closure, true, true);\n    return closure.contains(left.getInternalName());\n  }\n\n  public static boolean isAssignable(\n      Type[] args1, Type[] args2, ClassLoader cl, boolean exactTypeCheck) {\n    if (args1.length != args2.length) {\n      return false;\n    }\n    for (int i = 0; i < args1.length; i++) {\n      if (!args1[i].equals(args2[i])) {\n        int sort2 = args2[i].getSort();\n        /*\n         * if destination is AnyType and right side is\n         * Object or Array (i.e., any reference type)\n         * then we allow it - because AnyType is mapped to\n         * java.lang.Object.\n         */\n        if (!(isAnyType(args1[i])\n            && (sort2 == Type.OBJECT || sort2 == Type.ARRAY || isPrimitive(args2[i])))) {\n          if (!isAssignable(args1[i], args2[i], cl, exactTypeCheck)) {\n            return false;\n          }\n        }\n      }\n    }\n    return true;\n  }\n\n  public static String arrayDescriptorFor(int typeCode) {\n    switch (typeCode) {\n      case T_BOOLEAN:\n        return \"[Z\";\n      case T_CHAR:\n        return \"[C\";\n      case T_FLOAT:\n        return \"[F\";\n      case T_DOUBLE:\n        return \"[D\";\n      case T_BYTE:\n        return \"[B\";\n      case T_SHORT:\n        return \"[S\";\n      case T_INT:\n        return \"[I\";\n      case T_LONG:\n        return \"[J\";\n      default:\n        throw new IllegalArgumentException();\n    }\n  }\n\n  public static void accept(BTraceClassReader reader, ClassVisitor visitor) {\n    accept(reader, visitor, 0);\n  }\n\n  public static void accept(BTraceClassReader reader, ClassVisitor visitor, int flags) {\n    if (reader == null || visitor == null) return;\n\n    reader.accept(visitor, flags);\n  }\n\n  private static boolean isJDK16OrAbove(byte[] code) {\n    return isJDK16OrAbove(getMajor(code));\n  }\n\n  private static boolean isJDK16OrAbove(BTraceClassReader cr) {\n    return isJDK16OrAbove(getMajor(cr));\n  }\n\n  private static boolean isJDK16OrAbove(int major) {\n    return major >= 50;\n  }\n\n  private static int getMajor(BTraceClassReader cr) {\n    return cr.getClassVersion();\n  }\n\n  private static int getMajor(byte[] code) {\n    // skip 0xCAFEBABE magic and minor version\n    int majorOffset = 4 + 2;\n    return (((code[majorOffset] << 8) & 0xFF00) | ((code[majorOffset + 1]) & 0xFF));\n  }\n\n  public static ClassWriter newClassWriter() {\n    return newClassWriter(false);\n  }\n\n  public static ClassWriter newClassWriter(boolean computeFrames) {\n    return newClassWriter(computeFrames, false);\n  }\n\n  public static ClassWriter newClassWriter(boolean computeFrames, boolean computeMaxs) {\n    int flags = CW_FLAGS;\n    if (computeFrames) {\n      flags |= ClassWriter.COMPUTE_FRAMES;\n    }\n    if (computeMaxs) {\n      flags |= ClassWriter.COMPUTE_MAXS;\n    }\n    return newClassWriter(null, flags);\n  }\n\n  static BTraceClassWriter newClassWriter(BTraceClassReader cr) {\n    return newClassWriter(cr, CW_FLAGS);\n  }\n\n  static BTraceClassWriter newClassWriter(BTraceClassReader reader, int flags) {\n    BTraceClassWriter cw;\n    cw =\n        reader != null\n            ? new BTraceClassWriter(reader.getClassLoader(), reader, flags)\n            : new BTraceClassWriter(null, flags);\n\n    return cw;\n  }\n\n  static BTraceClassReader newClassReader(byte[] code) {\n    return new BTraceClassReader(ClassLoader.getSystemClassLoader(), code);\n  }\n\n  static BTraceClassReader newClassReader(ClassLoader cl, byte[] code) {\n    return new BTraceClassReader(cl, code);\n  }\n\n  static BTraceClassReader newClassReader(InputStream is) throws IOException {\n    return new BTraceClassReader(ClassLoader.getSystemClassLoader(), is);\n  }\n\n  static BTraceClassReader newClassReader(ClassLoader cl, InputStream is) throws IOException {\n    return new BTraceClassReader(cl, is);\n  }\n\n  static String getActionPrefix(String className) {\n    return Constants.BTRACE_METHOD_PREFIX + className.replace('/', '$') + \"$\";\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/InstrumentationException.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\n/**\n * Thrown when bytecode instrumentation fails due to invalid variable mapping, corrupted state, or\n * other instrumentation logic errors.\n *\n * <p>This exception indicates a bug in the instrumentation logic and provides detailed debug\n * information to help diagnose the issue. When thrown, instrumentation will fail gracefully,\n * returning the original unmodified class to prevent crashes in the instrumented application.\n *\n * @author BTrace Team\n * @since 2.3\n */\npublic class InstrumentationException extends RuntimeException {\n  public InstrumentationException(String message) {\n    super(message);\n  }\n\n  public InstrumentationException(String message, Throwable cause) {\n    super(message, cause);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/InstrumentingMethodVisitor.java",
    "content": "/*\n * Copyright (c) 2017, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\nimport org.objectweb.asm.AnnotationVisitor;\nimport org.objectweb.asm.Handle;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\nimport org.objectweb.asm.TypePath;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A method visitor providing support for introducing new local variables in bytecode recomputing\n * stackmap frames as necessary. It also provides an API for downstream visitors to hint insertion\n * of stackmap frames at required locations.\n */\npublic final class InstrumentingMethodVisitor extends MethodVisitor\n    implements MethodInstrumentorHelper {\n  private static final Logger log = LoggerFactory.getLogger(InstrumentingMethodVisitor.class);\n\n  interface FrameDiagnosticListener {\n    void onFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack);\n  }\n\n  static final Object TOP_EXT = -2;\n  private final VariableMapper variableMapper;\n  private final SimulatedStack stack = new SimulatedStack();\n  private final List<Object> locals = new ArrayList<>();\n  private final Set<LocalVarSlot> newLocals = new HashSet<>(3);\n  private final LocalVarTypes localTypes = new LocalVarTypes();\n  private final Set<Integer> frameOffsets = new HashSet<>();\n  private final Map<Label, SavedState> jumpTargetStates = new HashMap<>();\n  private final Map<Label, Set<Label>> tryCatchHandlerMap = new HashMap<>();\n  private final Map<Integer, MethodTrackingContext> trackingContexts = new HashMap<>();\n  private final String owner;\n  private final String desc;\n  private int argsSize = 0;\n  private boolean shouldCacheLevelVar = false;\n  private int localsTailPtr = 0;\n  private int pc = 0, lastFramePc = Integer.MIN_VALUE;\n  private final FrameDiagnosticListener frameDiagnosticListener;\n\n  public InstrumentingMethodVisitor(int access, String owner, String name, String desc, MethodVisitor mv) {\n    this(access, owner, name, desc, mv, (type, nLocal, local, nStack, stack) -> {});\n  }\n\n  InstrumentingMethodVisitor(\n      int access,\n      String owner,\n      String name,\n      String desc,\n      MethodVisitor mv,\n      FrameDiagnosticListener frameDiagnosticListener) {\n    super(ASM9, mv);\n    this.owner = owner;\n    this.desc = desc;\n\n    initLocals((access & ACC_STATIC) == 0, \"<init>\".equals(name));\n    variableMapper = new VariableMapper(argsSize);\n    this.frameDiagnosticListener = frameDiagnosticListener;\n  }\n\n  private static Object toSlotType(Type t) {\n    if (t == null) {\n      return null;\n    }\n    switch (t.getSort()) {\n      case Type.BOOLEAN:\n      case Type.CHAR:\n      case Type.BYTE:\n      case Type.SHORT:\n      case Type.INT:\n        {\n          return INTEGER;\n        }\n      case Type.FLOAT:\n        {\n          return FLOAT;\n        }\n      case Type.LONG:\n        {\n          return LONG;\n        }\n      case Type.DOUBLE:\n        {\n          return DOUBLE;\n        }\n      default:\n        {\n          return t == Constants.NULL_TYPE\n              ? NULL\n              : (t == Constants.TOP_TYPE ? TOP : t.getInternalName());\n        }\n    }\n  }\n\n  /**\n   * Normalizes a frame array by replacing BTrace-specific TOP_EXT markers with ASM's TOP constant.\n   * TOP_EXT is used internally to mark the second slot of long/double values, but ASM expects TOP\n   * instead.\n   */\n  private static Object[] normalizeFrameArray(Object[] arr) {\n    if (arr == null || arr.length == 0) {\n      return arr;\n    }\n    Object[] result = new Object[arr.length];\n    for (int i = 0; i < arr.length; i++) {\n      result[i] = arr[i] == TOP_EXT ? TOP : arr[i];\n    }\n    return result;\n  }\n\n  @Override\n  public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {\n    if (lastFramePc == pc) {\n      return;\n    }\n    lastFramePc = pc;\n\n    switch (type) {\n      case F_NEW: // fallthrough\n      case F_FULL:\n        {\n          locals.clear();\n          this.stack.reset();\n\n          if (nLocal > 0 && locals != null) {\n            locals.addAll(Arrays.asList(local).subList(0, nLocal));\n            localsTailPtr = nLocal;\n          } else {\n            localsTailPtr = 0;\n          }\n\n          if (nStack > 0 && stack != null) {\n            for (int i = 0; i < nStack; i++) {\n              Object e = stack[i];\n              this.stack.push(e);\n            }\n          }\n          break;\n        }\n      case F_SAME:\n        {\n          this.stack.reset();\n          break;\n        }\n      case F_SAME1:\n        {\n          this.stack.reset();\n          Object e = stack[0];\n          this.stack.push(e);\n          break;\n        }\n      case F_APPEND:\n        {\n          this.stack.reset();\n          int top = locals.size();\n          for (int i = 0; i < nLocal; i++) {\n            Object e = local[i];\n            if (localsTailPtr < top) {\n              locals.set(localsTailPtr, e);\n            } else {\n              locals.add(e);\n            }\n            localsTailPtr++;\n          }\n          break;\n        }\n      case F_CHOP:\n        {\n          this.stack.reset();\n          for (int i = 0; i < nLocal; i++) {\n            locals.remove(--localsTailPtr);\n          }\n          break;\n        }\n    }\n\n    Object[] localsArr = computeFrameLocals();\n    localTypes.replaceWith(localsArr);\n\n    int off = 0;\n    for (int i = 0; i < localsArr.length; i++) {\n      Object val = localsArr[i];\n      if (val == TOP_EXT) {\n        off++;\n        continue;\n      }\n      if (off > 0) {\n        localsArr[i - off] = localsArr[i];\n      }\n    }\n    localsArr = Arrays.copyOf(localsArr, localsArr.length - off);\n    Object[] tmpStack = this.stack.toArray(true);\n\n    superVisitFrame(F_NEW, localsArr.length, localsArr, tmpStack.length, tmpStack);\n  }\n\n  void superVisitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {\n    frameDiagnosticListener.onFrame(type, nLocal, local, nStack, stack);\n    super.visitFrame(type, nLocal, local, nStack, stack);\n  }\n\n  @Override\n  public void visitMultiANewArrayInsn(String arrayTypeName, int dims) {\n    Type arrayType = Type.getObjectType(arrayTypeName);\n    for (int i = 0; i < dims; i++) {\n      stack.pop();\n    }\n    stack.push(arrayType.getDescriptor());\n    super.visitMultiANewArrayInsn(arrayTypeName, dims);\n    pc++;\n  }\n\n  @Override\n  public void visitLookupSwitchInsn(Label label, int[] ints, Label[] labels) {\n    stack.pop();\n    SavedState state = new SavedState(localTypes, stack, newLocals, SavedState.CONDITIONAL);\n    jumpTargetStates.put(label, state);\n    for (Label l : labels) {\n      jumpTargetStates.put(l, state);\n    }\n    super.visitLookupSwitchInsn(label, ints, labels);\n    pc++;\n  }\n\n  @Override\n  public void visitTableSwitchInsn(int i, int i1, Label label, Label... labels) {\n    stack.pop();\n    SavedState state = new SavedState(localTypes, stack, newLocals, SavedState.CONDITIONAL);\n    jumpTargetStates.put(label, state);\n    for (Label l : labels) {\n      jumpTargetStates.put(l, state);\n    }\n    super.visitTableSwitchInsn(i, i1, label, labels);\n    pc++;\n  }\n\n  @Override\n  public void visitLdcInsn(Object o) {\n    Type t = Type.getType(o.getClass());\n    switch (t.getInternalName()) {\n      case \"java/lang/Integer\":\n        {\n          pushToStack(Type.INT_TYPE);\n          break;\n        }\n      case \"java/lang/Long\":\n        {\n          pushToStack(Type.LONG_TYPE);\n          break;\n        }\n      case \"java/lang/Byte\":\n        {\n          pushToStack(Type.BYTE_TYPE);\n          break;\n        }\n      case \"java/lang/Short\":\n        {\n          pushToStack(Type.SHORT_TYPE);\n          break;\n        }\n      case \"java/lang/Character\":\n        {\n          pushToStack(Type.CHAR_TYPE);\n          break;\n        }\n      case \"java/lang/Boolean\":\n        {\n          pushToStack(Type.BOOLEAN_TYPE);\n          break;\n        }\n      case \"java/lang/Float\":\n        {\n          pushToStack(Type.FLOAT_TYPE);\n          break;\n        }\n      case \"java/lang/Double\":\n        {\n          pushToStack(Type.DOUBLE_TYPE);\n          break;\n        }\n      default:\n        {\n          pushToStack(t);\n        }\n    }\n    super.visitLdcInsn(o);\n    pc++;\n  }\n\n  @Override\n  public void visitJumpInsn(int opcode, Label label) {\n    super.visitJumpInsn(opcode, label);\n    pc++;\n    switch (opcode) {\n      case IFEQ:\n      case IFGE:\n      case IFGT:\n      case IFLE:\n      case IFLT:\n      case IFNE:\n      case IFNONNULL:\n      case IFNULL:\n        {\n          stack.pop();\n          break;\n        }\n      case IF_ACMPEQ:\n      case IF_ACMPNE:\n      case IF_ICMPEQ:\n      case IF_ICMPGE:\n      case IF_ICMPGT:\n      case IF_ICMPLE:\n      case IF_ICMPLT:\n      case IF_ICMPNE:\n        {\n          stack.pop();\n          stack.pop();\n          break;\n        }\n    }\n    jumpTargetStates.put(\n        label,\n        new SavedState(\n            localTypes,\n            stack,\n            newLocals,\n            opcode == GOTO || opcode == JSR ? SavedState.UNCONDITIONAL : SavedState.CONDITIONAL));\n  }\n\n  @Override\n  public void visitInvokeDynamicInsn(String name, String desc, Handle handle, Object... bsmArgs) {\n    Type[] args = Type.getArgumentTypes(desc);\n    Type ret = Type.getReturnType(desc);\n\n    for (int i = args.length - 1; i >= 0; i--) {\n      if (!args[i].equals(Type.VOID_TYPE)) {\n        popFromStack(args[i]);\n      }\n    }\n    super.visitInvokeDynamicInsn(name, desc, handle, bsmArgs);\n    pc++;\n\n    if (!ret.equals(Type.VOID_TYPE)) {\n      pushToStack(ret);\n    }\n  }\n\n  @Override\n  public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itfc) {\n    Type[] args = Type.getArgumentTypes(desc);\n    Type ret = Type.getReturnType(desc);\n\n    for (int i = args.length - 1; i >= 0; i--) {\n      if (!args[i].equals(Type.VOID_TYPE)) {\n        popFromStack(args[i]);\n      }\n    }\n\n    if (opcode != INVOKESTATIC) {\n      stack.pop();\n    }\n    super.visitMethodInsn(opcode, owner, name, desc, itfc);\n    pc++;\n\n    if (!ret.equals(Type.VOID_TYPE)) {\n      pushToStack(ret);\n    }\n    if (opcode == INVOKESPECIAL && name.equals(\"<init>\")) {\n      if (stack.peek() instanceof Label) {\n        stack.pop();\n        pushToStack(Type.getObjectType(owner));\n      } else {\n        Object obj = stack.peek();\n        // uninitialized this becomes initialized after call to super <init>\n        if (!(obj instanceof String)) {\n          locals.replaceAll(o -> o == UNINITIALIZED_THIS ? this.owner : o);\n          localTypes.resolveUnitializedThis(this.owner);\n        }\n      }\n    }\n  }\n\n  @Override\n  public void visitFieldInsn(int opcode, String owner, String name, String desc) {\n    Type t = Type.getType(desc);\n    super.visitFieldInsn(opcode, owner, name, desc);\n    pc++;\n\n    if (opcode == PUTFIELD || opcode == PUTSTATIC) {\n      popFromStack(t);\n    }\n    if (opcode == GETFIELD || opcode == PUTFIELD) {\n      stack.pop(); // pop 'this'\n    }\n    if (opcode == GETFIELD || opcode == GETSTATIC) {\n      pushToStack(t);\n    }\n  }\n\n  @Override\n  public void visitTypeInsn(int opcode, String type) {\n    super.visitTypeInsn(opcode, type);\n    pc++;\n\n    switch (opcode) {\n      case NEW:\n        {\n          pushToStack(Type.getObjectType(type));\n          break;\n        }\n      case ANEWARRAY:\n        {\n          stack.pop();\n          Type elementType = type.endsWith(\";\") ? Type.getType(type) : Type.getObjectType(type);\n          Type arrayType = Type.getType(\"[\" + elementType);\n          pushToStack(arrayType);\n          break;\n        }\n      case INSTANCEOF:\n        {\n          stack.pop();\n          pushToStack(Type.BOOLEAN_TYPE);\n          break;\n        }\n      case CHECKCAST:\n        {\n          stack.pop();\n          pushToStack(Type.getObjectType(type));\n          break;\n        }\n    }\n  }\n\n  @Override\n  public void visitVarInsn(int opcode, int var) {\n    int size = 1;\n\n    switch (opcode) {\n      case DLOAD:\n      case LLOAD:\n      case DSTORE:\n      case LSTORE:\n        {\n          size++;\n          break;\n        }\n    }\n    var = variableMapper.remap(var, size);\n\n    boolean isPush = false;\n    Type opType = null;\n    switch (opcode) {\n      case ILOAD:\n        {\n          opType = Type.INT_TYPE;\n          isPush = true;\n          break;\n        }\n      case LLOAD:\n        {\n          opType = Type.LONG_TYPE;\n          isPush = true;\n          break;\n        }\n      case FLOAD:\n        {\n          opType = Type.FLOAT_TYPE;\n          isPush = true;\n          break;\n        }\n      case DLOAD:\n        {\n          opType = Type.DOUBLE_TYPE;\n          isPush = true;\n          break;\n        }\n      case ALOAD:\n        {\n          Object o = localTypes.getType(var);\n          opType = fromSlotType(o);\n          isPush = true;\n          break;\n        }\n      case ISTORE:\n        {\n          opType = Type.INT_TYPE;\n          break;\n        }\n      case LSTORE:\n        {\n          opType = Type.LONG_TYPE;\n          break;\n        }\n      case FSTORE:\n        {\n          opType = Type.FLOAT_TYPE;\n          break;\n        }\n      case DSTORE:\n        {\n          opType = Type.DOUBLE_TYPE;\n          break;\n        }\n      case ASTORE:\n        {\n          opType = fromSlotType(stack.peek());\n          break;\n        }\n    }\n\n    assert opType != null;\n\n    if (isPush) {\n      pushToStack(opType);\n    } else {\n      popFromStack(opType);\n      localTypes.setType(var, opType);\n    }\n\n    super.visitVarInsn(opcode, var);\n    pc++;\n  }\n\n  @Override\n  public void visitIntInsn(int opcode, int operand) {\n    super.visitIntInsn(opcode, operand);\n    pc++;\n\n    switch (opcode) {\n      case BIPUSH:\n      case SIPUSH:\n        {\n          stack.push(INTEGER);\n          break;\n        }\n      case NEWARRAY:\n        {\n          popFromStack(Type.INT_TYPE); // size\n          switch (operand) {\n            case T_BOOLEAN:\n              {\n                pushToStack(Type.getObjectType(\"[Z\"));\n                break;\n              }\n            case T_CHAR:\n              {\n                pushToStack(Type.getObjectType(\"[C\"));\n                break;\n              }\n            case T_FLOAT:\n              {\n                pushToStack(Type.getObjectType(\"[F\"));\n                break;\n              }\n            case T_DOUBLE:\n              {\n                pushToStack(Type.getObjectType(\"[D\"));\n                break;\n              }\n            case T_BYTE:\n              {\n                pushToStack(Type.getObjectType(\"[B\"));\n                break;\n              }\n            case T_SHORT:\n              {\n                pushToStack(Type.getObjectType(\"[S\"));\n                break;\n              }\n            case T_INT:\n              {\n                pushToStack(Type.getObjectType(\"[I\"));\n                break;\n              }\n            case T_LONG:\n              {\n                pushToStack(Type.getObjectType(\"[J\"));\n                break;\n              }\n          }\n          break;\n        }\n    }\n  }\n\n  @Override\n  public void visitInsn(int opcode) {\n    super.visitInsn(opcode);\n    pc++;\n\n    switch (opcode) {\n      case ACONST_NULL:\n        {\n          stack.push(NULL);\n          break;\n        }\n      case ICONST_0:\n      case ICONST_1:\n      case ICONST_2:\n      case ICONST_3:\n      case ICONST_4:\n      case ICONST_5:\n      case ICONST_M1:\n        {\n          pushToStack(Type.INT_TYPE);\n          break;\n        }\n      case FCONST_0:\n      case FCONST_1:\n      case FCONST_2:\n        {\n          pushToStack(Type.FLOAT_TYPE);\n          break;\n        }\n      case LCONST_0:\n      case LCONST_1:\n        {\n          pushToStack(Type.LONG_TYPE);\n          break;\n        }\n      case DCONST_0:\n      case DCONST_1:\n        {\n          pushToStack(Type.DOUBLE_TYPE);\n          break;\n        }\n      case AALOAD:\n        {\n          stack.pop(); // index\n          Object target = stack.pop();\n\n          if (target instanceof String) {\n            Type t;\n            String typeStr = (String) target;\n            if (typeStr.startsWith(\"[\")) {\n              if (typeStr.contains(\"/\") && !typeStr.endsWith(\";\")) {\n                typeStr += \";\";\n              }\n              // Type.getElementType() will give the non-array type which we don't want here\n              // For a multi-dimensional array the element type is the lower dimension array\n              typeStr = typeStr.substring(1);\n              t = Type.getType(typeStr);\n            } else {\n              t = Type.getObjectType(typeStr);\n            }\n            pushToStack(t);\n          } else if (target == NULL) {\n            pushToStack(Constants.NULL_TYPE);\n          } else {\n            pushToStack(Constants.OBJECT_TYPE);\n          }\n          break;\n        }\n      case IALOAD:\n        {\n          stack.pop();\n          stack.pop();\n\n          pushToStack(Type.INT_TYPE);\n          break;\n        }\n      case FALOAD:\n        {\n          stack.pop();\n          stack.pop();\n\n          pushToStack(Type.FLOAT_TYPE);\n          break;\n        }\n      case BALOAD:\n        {\n          stack.pop();\n          stack.pop();\n\n          pushToStack(Type.BYTE_TYPE);\n          break;\n        }\n      case CALOAD:\n        {\n          stack.pop();\n          stack.pop();\n\n          pushToStack(Type.CHAR_TYPE);\n          break;\n        }\n      case SALOAD:\n        {\n          stack.pop();\n          stack.pop();\n\n          pushToStack(Type.SHORT_TYPE);\n          break;\n        }\n      case LALOAD:\n        {\n          stack.pop();\n          stack.pop();\n\n          pushToStack(Type.LONG_TYPE);\n          break;\n        }\n      case DALOAD:\n        {\n          stack.pop();\n          stack.pop();\n\n          pushToStack(Type.DOUBLE_TYPE);\n          break;\n        }\n      case AASTORE:\n      case IASTORE:\n      case FASTORE:\n      case BASTORE:\n      case CASTORE:\n      case SASTORE:\n      case LASTORE:\n      case DASTORE:\n        {\n          stack.pop(); // val\n          stack.pop(); // index\n          stack.pop(); // arrayref\n\n          break;\n        }\n      case POP:\n        {\n          stack.pop1();\n          break;\n        }\n      case POP2:\n        {\n          stack.pop1();\n          stack.pop1();\n          break;\n        }\n      case DUP:\n        {\n          stack.push1(stack.peek());\n          break;\n        }\n      case DUP_X1:\n        {\n          Object x = stack.pop1();\n          Object y = stack.pop1();\n          stack.push1(x);\n          stack.push1(y);\n          stack.push1(x);\n          break;\n        }\n      case DUP_X2:\n        {\n          Object x = stack.pop1();\n          Object y = stack.pop1();\n          Object z = stack.pop1();\n          stack.push1(x);\n          stack.push1(z);\n          stack.push1(y);\n          stack.push1(x);\n          break;\n        }\n      case DUP2:\n        {\n          Object x = stack.pop1();\n          Object y = stack.peek();\n          stack.push1(x);\n          stack.push1(y);\n          stack.push1(x);\n          break;\n        }\n      case DUP2_X1:\n        {\n          Object x2 = stack.pop1();\n          Object x1 = stack.pop1();\n          Object y = stack.pop1();\n          stack.push1(x1);\n          stack.push1(x2);\n          stack.push1(y);\n          stack.push1(x1);\n          stack.push1(x2);\n          break;\n        }\n      case DUP2_X2:\n        {\n          Object x2 = stack.pop1();\n          Object x1 = stack.pop1();\n          Object y2 = stack.pop1();\n          Object y1 = stack.pop1();\n          stack.push1(x1);\n          stack.push1(x2);\n          stack.push1(y1);\n          stack.push1(y2);\n          stack.push1(x1);\n          stack.push1(x2);\n          break;\n        }\n      case SWAP:\n        {\n          Object x = stack.pop1();\n          Object y = stack.pop1();\n          stack.push1(x);\n          stack.push1(y);\n          break;\n        }\n      case IADD:\n      case ISUB:\n      case IMUL:\n      case IDIV:\n      case IREM:\n      case IAND:\n      case IOR:\n      case IXOR:\n      case ISHR:\n      case ISHL:\n      case IUSHR:\n        {\n          popFromStack(Type.INT_TYPE);\n          popFromStack(Type.INT_TYPE);\n          pushToStack(Type.INT_TYPE);\n          break;\n        }\n      case FADD:\n      case FSUB:\n      case FMUL:\n      case FDIV:\n      case FREM:\n        {\n          popFromStack(Type.FLOAT_TYPE);\n          popFromStack(Type.FLOAT_TYPE);\n          pushToStack(Type.FLOAT_TYPE);\n          break;\n        }\n      case LADD:\n      case LSUB:\n      case LMUL:\n      case LDIV:\n      case LREM:\n      case LAND:\n      case LOR:\n      case LXOR:\n        {\n          popFromStack(Type.LONG_TYPE);\n          popFromStack(Type.LONG_TYPE);\n          pushToStack(Type.LONG_TYPE);\n          break;\n        }\n      case LSHR:\n      case LSHL:\n      case LUSHR:\n        {\n          popFromStack(Type.INT_TYPE);\n          popFromStack(Type.LONG_TYPE);\n          pushToStack(Type.LONG_TYPE);\n          break;\n        }\n      case DADD:\n      case DSUB:\n      case DMUL:\n      case DDIV:\n      case DREM:\n        {\n          popFromStack(Type.DOUBLE_TYPE);\n          popFromStack(Type.DOUBLE_TYPE);\n          pushToStack(Type.DOUBLE_TYPE);\n          break;\n        }\n      case I2L:\n        {\n          popFromStack(Type.INT_TYPE);\n          pushToStack(Type.LONG_TYPE);\n          break;\n        }\n      case I2F:\n        {\n          popFromStack(Type.INT_TYPE);\n          pushToStack(Type.FLOAT_TYPE);\n          break;\n        }\n      case I2B:\n        {\n          popFromStack(Type.INT_TYPE);\n          pushToStack(Type.BYTE_TYPE);\n          break;\n        }\n      case I2C:\n        {\n          popFromStack(Type.INT_TYPE);\n          pushToStack(Type.CHAR_TYPE);\n          break;\n        }\n      case I2S:\n        {\n          popFromStack(Type.INT_TYPE);\n          pushToStack(Type.SHORT_TYPE);\n          break;\n        }\n      case I2D:\n        {\n          popFromStack(Type.INT_TYPE);\n          pushToStack(Type.DOUBLE_TYPE);\n          break;\n        }\n      case L2I:\n        {\n          popFromStack(Type.LONG_TYPE);\n          pushToStack(Type.INT_TYPE);\n          break;\n        }\n      case L2F:\n        {\n          popFromStack(Type.LONG_TYPE);\n          pushToStack(Type.FLOAT_TYPE);\n          break;\n        }\n      case L2D:\n        {\n          popFromStack(Type.LONG_TYPE);\n          pushToStack(Type.DOUBLE_TYPE);\n          break;\n        }\n      case F2I:\n        {\n          popFromStack(Type.FLOAT_TYPE);\n          pushToStack(Type.INT_TYPE);\n          break;\n        }\n      case F2L:\n        {\n          popFromStack(Type.FLOAT_TYPE);\n          pushToStack(Type.LONG_TYPE);\n          break;\n        }\n      case F2D:\n        {\n          popFromStack(Type.FLOAT_TYPE);\n          pushToStack(Type.DOUBLE_TYPE);\n          break;\n        }\n      case D2I:\n        {\n          popFromStack(Type.DOUBLE_TYPE);\n          pushToStack(Type.INT_TYPE);\n          break;\n        }\n      case D2F:\n        {\n          popFromStack(Type.DOUBLE_TYPE);\n          pushToStack(Type.FLOAT_TYPE);\n          break;\n        }\n      case D2L:\n        {\n          popFromStack(Type.DOUBLE_TYPE);\n          pushToStack(Type.LONG_TYPE);\n          break;\n        }\n      case LCMP:\n        {\n          popFromStack(Type.LONG_TYPE);\n          popFromStack(Type.LONG_TYPE);\n\n          pushToStack(Type.INT_TYPE);\n          break;\n        }\n      case FCMPL:\n      case FCMPG:\n        {\n          popFromStack(Type.FLOAT_TYPE);\n          popFromStack(Type.FLOAT_TYPE);\n\n          pushToStack(Type.INT_TYPE);\n          break;\n        }\n      case DCMPL:\n      case DCMPG:\n        {\n          popFromStack(Type.DOUBLE_TYPE);\n          popFromStack(Type.DOUBLE_TYPE);\n\n          pushToStack(Type.INT_TYPE);\n          break;\n        }\n      case IRETURN:\n        {\n          popFromStack(Type.INT_TYPE);\n          break;\n        }\n      case LRETURN:\n        {\n          popFromStack(Type.LONG_TYPE);\n          break;\n        }\n      case FRETURN:\n        {\n          popFromStack(Type.FLOAT_TYPE);\n          break;\n        }\n      case DRETURN:\n        {\n          popFromStack(Type.DOUBLE_TYPE);\n          break;\n        }\n      case ARETURN:\n        {\n          popFromStack(Type.getReturnType(desc));\n          break;\n        }\n      case ATHROW:\n        {\n          popFromStack(Constants.THROWABLE_TYPE);\n          break;\n        }\n      case ARRAYLENGTH:\n        {\n          stack.pop();\n          pushToStack(Type.INT_TYPE);\n          break;\n        }\n      case MONITORENTER:\n      case MONITOREXIT:\n        {\n          stack.pop();\n          break;\n        }\n    }\n  }\n\n  @Override\n  public void visitIincInsn(int var, int increment) {\n    super.visitIincInsn(variableMapper.remap(var, 1), increment);\n    pc++;\n  }\n\n  @Override\n  public void visitLocalVariable(\n      String name, String desc, String signature, Label start, Label end, int index) {\n    try {\n      int newIndex = variableMapper.map(index, start);\n      super.visitLocalVariable(\n          name, desc, signature, start, end, newIndex == Integer.MIN_VALUE ? 0 : newIndex);\n    } catch (InstrumentationException e) {\n      throw new InstrumentationException(\n          String.format(\n              \"Failed to map local variable '%s' (type=%s, index=%d, scope=%s): %s\",\n              name, desc, index, start, e.getMessage()),\n          e);\n    }\n  }\n\n  @Override\n  public AnnotationVisitor visitLocalVariableAnnotation(\n      int typeRef,\n      TypePath typePath,\n      Label[] start,\n      Label[] end,\n      int[] index,\n      String desc,\n      boolean visible) {\n    try {\n      int[] newIndex = new int[index.length];\n      for (int i = 0; i < index.length; i++) {\n        newIndex[i] = variableMapper.map(index[i]);\n      }\n      return super.visitLocalVariableAnnotation(\n          typeRef, typePath, start, end, newIndex, desc, visible);\n    } catch (InstrumentationException e) {\n      throw new InstrumentationException(\n          String.format(\n              \"Failed to map local variable annotation (type=%s, indices=%s): %s\",\n              desc, Arrays.toString(index), e.getMessage()),\n          e);\n    }\n  }\n\n  @Override\n  public void visitTryCatchBlock(Label start, Label end, Label handler, String exception) {\n    addTryCatchHandler(start, handler);\n    super.visitTryCatchBlock(start, end, handler, exception);\n  }\n\n  @Override\n  public void visitLabel(Label label) {\n    variableMapper.noteLabel(label);\n    SavedState ss = jumpTargetStates.get(label);\n    if (ss != null) {\n      if (ss.kind != SavedState.CONDITIONAL) {\n        reset();\n      }\n      localTypes.mergeWith(ss.lvTypes.toArray());\n      stack.replaceWith(ss.sStack.toArray());\n      if (ss.kind == SavedState.EXCEPTION) {\n        stack.push(toSlotType(Constants.THROWABLE_TYPE));\n      }\n      for (LocalVarSlot lvs : newLocals) {\n        if (!ss.newLocals.contains(lvs)) {\n          lvs.expire();\n        }\n      }\n      newLocals.clear();\n      newLocals.addAll(ss.newLocals);\n    }\n    Set<Label> handlers = tryCatchHandlerMap.get(label);\n    if (handlers != null) {\n      for (Label handler : handlers) {\n        if (!jumpTargetStates.containsKey(handler)) {\n          jumpTargetStates.put(\n              handler, new SavedState(localTypes, stack, newLocals, SavedState.EXCEPTION));\n        }\n      }\n    }\n    super.visitLabel(label);\n  }\n\n  @Override\n  public void visitMaxs(int maxStack, int maxLocals) {\n    super.visitMaxs(Math.max(stack.maxStack, maxStack), localTypes.maxSize());\n  }\n\n  @Override\n  public void insertFrameReplaceStack(Label l, Type... stackTypes) {\n    if (pc == lastFramePc) {\n      return;\n    }\n    lastFramePc = pc;\n\n    if (!frameOffsets.add(l.getOffset()) || !jumpTargetStates.containsKey(l)) {\n      return;\n    }\n\n    Object[] localsArr = trimLocalVars(localTypes.toArray(true));\n\n    stack.reset();\n    for (Type t : stackTypes) {\n      stack.push(toSlotType(t));\n    }\n\n    Object[] stackSlots = stack.toArray(true);\n\n    superVisitFrame(F_NEW, localsArr.length, localsArr, stackSlots.length, stackSlots);\n  }\n\n  @Override\n  public void insertFrameAppendStack(Label l, Type... stackTypes) {\n    if (pc == lastFramePc) {\n      return;\n    }\n    lastFramePc = pc;\n\n    // Always allow explicit frame insertion at the requested label.\n    // Using frameOffsets prevents duplicates at the same offset.\n    if (!frameOffsets.add(l.getOffset())) {\n      return;\n    }\n\n    Object[] localsArr = trimLocalVars(localTypes.toArray(true));\n\n    for (Type t : stackTypes) {\n      stack.push(toSlotType(t));\n    }\n\n    Object[] stackSlots = stack.toArray(true);\n\n    superVisitFrame(F_NEW, localsArr.length, localsArr, stackSlots.length, stackSlots);\n  }\n\n  @Override\n  public void insertFrameSameStack(Label l) {\n    if (pc == lastFramePc) {\n      return;\n    }\n\n    // Always allow explicit frame insertion at the requested label.\n    // Using frameOffsets prevents duplicates at the same offset.\n    if (!frameOffsets.add(l.getOffset())) {\n      return;\n    }\n\n    lastFramePc = pc;\n\n    SavedState saved = jumpTargetStates.get(l);\n    Object[] localsArr = (saved != null ? saved.lvTypes : localTypes).toArray(true);\n    Object[] stackSlots = (saved != null ? saved.sStack : stack).toArray(true);\n\n    // Always use F_NEW for inserted frames to ensure correctness.\n    // Compressed frames (F_SAME, F_APPEND, etc.) require careful offset management\n    // and are better left to ASM's automatic frame computation or explicit visitFrame calls.\n    superVisitFrame(F_NEW, localsArr.length, localsArr, stackSlots.length, stackSlots);\n  }\n\n  @Override\n  public void addTryCatchHandler(Label start, Label handler) {\n    Set<Label> handlers = tryCatchHandlerMap.get(start);\n    if (handlers == null) {\n      handlers = new HashSet<>();\n    }\n    handlers.add(handler);\n    tryCatchHandlerMap.put(start, handlers);\n  }\n\n  @Override\n  public int storeAsNew() {\n    Type t = fromSlotType(peekFromStack());\n    int idx = newVar(t);\n    visitVarInsn(t.getOpcode(ISTORE), idx);\n    return idx;\n  }\n\n  @Override\n  public final int newVar(Type t) {\n    int size = t == Constants.NULL_TYPE ? 1 : t.getSize();\n    int idx = variableMapper.newVarIdx(size);\n\n    int var = VariableMapper.unmask(idx == Integer.MIN_VALUE ? 0 : idx);\n    newLocals.add(new LocalVarSlot(var, toSlotType(t)));\n\n    localTypes.setType(var, t);\n\n    return idx;\n  }\n\n  public void setShouldCacheLevelVar(boolean shouldCache) {\n    this.shouldCacheLevelVar = shouldCache;\n  }\n\n  public boolean shouldCacheLevelVar() {\n    return shouldCacheLevelVar;\n  }\n\n  @Override\n  public MethodTrackingContext getOrCreateTrackingContext(\n      int methodId, Supplier<MethodTrackingContext> factory) {\n    return trackingContexts.computeIfAbsent(methodId, k -> factory.get());\n  }\n\n  private void initLocals(boolean isInstance, boolean isConstructor) {\n    int nextMappedVar = 0;\n    if (isInstance) {\n      locals.add(isConstructor ? Opcodes.UNINITIALIZED_THIS : owner);\n      nextMappedVar++;\n      localsTailPtr++;\n    }\n    for (Type t : Type.getArgumentTypes(desc)) {\n      locals.add(toSlotType(t));\n      nextMappedVar += t.getSize();\n      localsTailPtr++;\n    }\n    localTypes.replaceWith(locals.toArray(new Object[0]));\n    argsSize = nextMappedVar;\n  }\n\n  private Object[] computeFrameLocals() {\n    return computeFrameLocals(argsSize, locals, newLocals, variableMapper);\n  }\n\n  // package accessible for targeted tests\n  static Object[] computeFrameLocals(\n      int argsSize,\n      List<Object> locals,\n      Set<LocalVarSlot> newLocals,\n      VariableMapper variableMapper) {\n    newLocals = newLocals != null ? newLocals : Collections.emptySet();\n    Object[] localsArr;\n    int nextMappedVar = variableMapper.getNextMappedVar();\n    if (nextMappedVar > argsSize) {\n      int arrSize = Math.max(locals.size(), nextMappedVar);\n      localsArr = new Object[arrSize];\n      int idx = 0;\n      for (Object e : locals) {\n        if (idx < argsSize) {\n          localsArr[idx] = e;\n          if (e == LONG || e == DOUBLE) {\n            localsArr[++idx] = TOP_EXT;\n          }\n        } else {\n          try {\n            int var = variableMapper.map(idx);\n            if (var >= localsArr.length) {\n              localsArr = Arrays.copyOf(localsArr, var + 1);\n            }\n            localsArr[var] = e;\n            if (e == LONG || e == DOUBLE) {\n              int off = var + 1;\n              if (off >= localsArr.length) {\n                localsArr = Arrays.copyOf(localsArr, off + 1);\n              }\n              localsArr[off] = TOP_EXT;\n              idx++;\n            }\n          } catch (InstrumentationException ex) {\n            // When locals haven't been remapped yet (common with early Duration instrumentation),\n            // proactively remap so stack frames stay consistent.\n            int size = (e == LONG || e == DOUBLE) ? 2 : 1;\n            int var = variableMapper.remap(idx, size);\n            int required = var + size;\n            if (required > localsArr.length) {\n              localsArr = Arrays.copyOf(localsArr, required);\n            }\n            localsArr[var] = e;\n            if (size == 2) {\n              int off = var + 1;\n              if (off >= localsArr.length) {\n                localsArr = Arrays.copyOf(localsArr, off + 1);\n              }\n              localsArr[off] = TOP_EXT;\n              idx++;\n            }\n          }\n        }\n        idx++;\n      }\n      if (!newLocals.isEmpty()) {\n        int required = localsArr.length;\n        for (LocalVarSlot lvs : newLocals) {\n          int ptr = lvs.idx != Integer.MIN_VALUE ? lvs.idx : 0;\n          int size = (lvs.type == LONG || lvs.type == DOUBLE) ? 2 : 1;\n          required = Math.max(required, ptr + size);\n        }\n        if (required > localsArr.length) {\n          localsArr = Arrays.copyOf(localsArr, required);\n        }\n        for (LocalVarSlot lvs : newLocals) {\n          int ptr = lvs.idx != Integer.MIN_VALUE ? lvs.idx : 0;\n          localsArr[ptr] = lvs.isExpired() ? TOP : lvs.type;\n          if (lvs.type == LONG || lvs.type == DOUBLE) {\n            localsArr[ptr + 1] = TOP_EXT;\n          }\n        }\n      }\n    } else {\n      // Expand compact locals list into slot-indexed array.\n      // The locals list stores LONG/DOUBLE as single entries but they\n      // occupy 2 JVM slots. We must insert TOP_EXT companions to\n      // prevent ensureTopExtSlots() from overwriting the next real local.\n      int slotCount = 0;\n      for (Object e : locals) {\n        slotCount += (e == LONG || e == DOUBLE) ? 2 : 1;\n      }\n      localsArr = new Object[slotCount];\n      int slot = 0;\n      for (Object e : locals) {\n        localsArr[slot++] = e;\n        if (e == LONG || e == DOUBLE) {\n          localsArr[slot++] = TOP_EXT;\n        }\n      }\n    }\n    for (int m : variableMapper.mappings()) {\n      if (m != 0) {\n        if (localsArr[m] == null) {\n          localsArr[m] = TOP;\n        }\n      }\n    }\n    localsArr = trimLocalVars(localsArr);\n    localsArr = ensureTopExtSlots(localsArr);\n    return localsArr;\n  }\n\n  private static Object[] ensureTopExtSlots(Object[] localsArr) {\n    if (localsArr == null || localsArr.length == 0) {\n      return localsArr;\n    }\n    Object[] arr = localsArr;\n    for (int i = 0; i < arr.length; i++) {\n      Object val = arr[i];\n      if (val == LONG || val == DOUBLE) {\n        int next = i + 1;\n        if (next >= arr.length) {\n          arr = Arrays.copyOf(arr, next + 1);\n          arr[next] = TOP_EXT;\n          i = next;\n          continue;\n        }\n        if (arr[next] == TOP_EXT) {\n          i = next;\n          continue;\n        }\n        arr = insertTopExtSlot(arr, next);\n        i = next;\n        continue;\n      }\n      if (val == TOP_EXT && (i == 0 || (arr[i - 1] != LONG && arr[i - 1] != DOUBLE))) {\n        arr = removeTopExtSlot(arr, i);\n        i--;\n      }\n    }\n    return arr;\n  }\n\n  private static Object[] insertTopExtSlot(Object[] arr, int index) {\n    Object[] expanded = Arrays.copyOf(arr, arr.length + 1);\n    System.arraycopy(arr, index, expanded, index + 1, arr.length - index);\n    expanded[index] = TOP_EXT;\n    return expanded;\n  }\n\n  private static Object[] removeTopExtSlot(Object[] arr, int index) {\n    Object[] compacted = new Object[arr.length - 1];\n    System.arraycopy(arr, 0, compacted, 0, index);\n    if (index < compacted.length) {\n      System.arraycopy(arr, index + 1, compacted, index, compacted.length - index);\n    }\n    return compacted;\n  }\n\n  private static Object[] trimLocalVars(Object[] localsArr) {\n    Object[] tmp = new Object[localsArr.length];\n    int idx = 0;\n    int firstEmpty = -1, emptyRunLen = 0;\n    for (Object o : localsArr) {\n      if (o == null) {\n        if (firstEmpty == -1) {\n          firstEmpty = idx;\n        }\n        emptyRunLen++;\n        tmp[idx++] = TOP;\n      } else if (o == TOP) {\n        if (firstEmpty == -1) {\n          firstEmpty = idx;\n        }\n        emptyRunLen++;\n        tmp[idx++] = TOP;\n      } else {\n        firstEmpty = -1;\n        emptyRunLen = 0;\n        tmp[idx++] = o;\n      }\n    }\n    if (firstEmpty > -1 && (firstEmpty + emptyRunLen) == localsArr.length) {\n      // the frame locals are ending with uninterrupted run of TOP slots; safe to cut them\n      return Arrays.copyOf(tmp, firstEmpty);\n    } else {\n      return Arrays.copyOf(tmp, idx);\n    }\n  }\n\n  private void reset() {\n    localTypes.reset();\n    stack.reset();\n    newLocals.clear();\n  }\n\n  private Object peekFromStack() {\n    Object o = stack.peek();\n    if (o == null || o == TOP_EXT) {\n      o = stack.peekX1();\n    }\n    return o;\n  }\n\n  @SuppressWarnings(\"UnusedReturnValue\")\n  private Object popFromStack(Type t) {\n    return stack.pop();\n  }\n\n  private void pushToStack(Type t) {\n    stack.push(toSlotType(t));\n  }\n\n  private Type fromSlotType(Object slotType) {\n    if (slotType == INTEGER) {\n      return Type.INT_TYPE;\n    }\n    if (slotType == FLOAT) {\n      return Type.FLOAT_TYPE;\n    }\n    if (slotType == LONG) {\n      return Type.LONG_TYPE;\n    }\n    if (slotType == DOUBLE) {\n      return Type.DOUBLE_TYPE;\n    }\n    if (slotType == UNINITIALIZED_THIS) {\n      return Type.getObjectType(owner);\n    }\n    if (slotType == NULL) {\n      return Constants.NULL_TYPE;\n    }\n    if (slotType == TOP) {\n      return Constants.TOP_TYPE;\n    }\n    if (slotType instanceof Integer) {\n      log.warn(\"Unknown slot type: {}\", slotType);\n      return Constants.OBJECT_TYPE;\n    }\n    return slotType != null ? Type.getObjectType((String) slotType) : Constants.OBJECT_TYPE;\n  }\n\n  static final class LocalVarSlot {\n    final int idx;\n    final Object type;\n    private boolean expired = false;\n\n    LocalVarSlot(int idx, Object type) {\n      this.idx = Math.abs(idx);\n      this.type = type;\n    }\n\n    void expire() {\n      expired = true;\n    }\n\n    boolean isExpired() {\n      return expired;\n    }\n\n    @Override\n    public int hashCode() {\n      int hash = 3;\n      hash = 97 * hash + idx;\n      return hash;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n      if (this == obj) {\n        return true;\n      }\n      if (obj == null) {\n        return false;\n      }\n      if (getClass() != obj.getClass()) {\n        return false;\n      }\n      LocalVarSlot other = (LocalVarSlot) obj;\n      return idx == other.idx;\n    }\n  }\n\n  static final class SimulatedStack {\n    private static final int DEFAULT_CAPACITY = 16;\n    private int stackPtr = 0;\n    private int maxStack = 0;\n    private Object[] stack = new Object[DEFAULT_CAPACITY];\n\n    public SimulatedStack() {}\n\n    SimulatedStack(Object[] other) {\n      replaceWith(other);\n    }\n\n    private void fitResize(int ptr) {\n      if (ptr >= stack.length) {\n        stack = Arrays.copyOf(stack, Math.max(stack.length * 2, stackPtr + 1));\n      }\n    }\n\n    public void push1(Object val) {\n      fitResize(stackPtr);\n      stack[stackPtr++] = val;\n      maxStack = Math.max(stackPtr, maxStack);\n    }\n\n    public void push(Object val) {\n      fitResize(stackPtr);\n\n      stack[stackPtr++] = val;\n      if (val == LONG || val == DOUBLE) {\n        fitResize(stackPtr);\n        stack[stackPtr++] = TOP_EXT;\n      }\n      maxStack = Math.max(stackPtr, maxStack);\n    }\n\n    public Object pop1() {\n      if (hasData()) {\n        return stack[--stackPtr];\n      }\n      return TOP;\n    }\n\n    public Object pop() {\n      if (hasData()) {\n        Object val = stack[--stackPtr];\n        if (val == TOP_EXT) {\n          val = stack[--stackPtr];\n        }\n        return val;\n      }\n      return TOP;\n    }\n\n    public Object peek() {\n      if (hasData()) {\n        return stack[stackPtr - 1];\n      }\n      return TOP;\n    }\n\n    @SuppressWarnings(\"SuspiciousNameCombination\")\n    public Object peekX1() {\n      if (stackPtr > 1) {\n        return stack[stackPtr - 2];\n      }\n      return TOP;\n    }\n\n    public Object peek(int offset) {\n      if (stackPtr > offset) {\n        return stack[stackPtr - offset - 1];\n      }\n      return TOP;\n    }\n\n    public boolean hasData() {\n      return stackPtr != 0;\n    }\n\n    public int size() {\n      return stackPtr;\n    }\n\n    public void reset() {\n      stackPtr = 0;\n      stack = new Object[DEFAULT_CAPACITY];\n    }\n\n    public Object[] toArray() {\n      return toArray(false);\n    }\n\n    public Object[] toArray(boolean compress) {\n      Object[] ret = new Object[stackPtr];\n      int localCnt = 0;\n      for (int i = 0; i < stackPtr; i++) {\n        Object o = stack[i];\n        if (o != null) {\n          if (compress && o == TOP_EXT) {\n            // When compressing for ASM API, skip TOP_EXT entirely.\n            // ASM's visitFrame() expects category-2 types (long/double) to be represented\n            // by a single element, NOT as [LONG, TOP] or [DOUBLE, TOP].\n            // See: ASM MethodVisitor API and JVMS Chapter 4\n            // - ASM API input: visitFrame(F_NEW, n, [LONG, LONG], ...)\n            // - JVMS bytecode output: Disassembles to [long, top, long, top]\n            // ASM handles the expansion from compact to JVMS format internally.\n            continue;\n          } else {\n            ret[localCnt++] = o;\n            // If this is a category-2 type, the next slot should be TOP_EXT (second half).\n            // Skip it to maintain compact ASM API format.\n            if (compress && (o == LONG || o == DOUBLE)) {\n              if (i + 1 < stackPtr && stack[i + 1] == TOP_EXT) {\n                i++; // Skip the TOP_EXT in next iteration\n              }\n            }\n          }\n        }\n      }\n      return Arrays.copyOf(ret, localCnt);\n    }\n\n    public void replaceWith(Object[] other) {\n      if (other.length > 0) {\n        Object[] arr = new Object[other.length * 2];\n        int idx = 0;\n        for (int ptr = 0; ptr < other.length; ptr++) {\n          Object o = other[ptr];\n          arr[idx++] = o;\n          if (o == DOUBLE || o == LONG) {\n            // Check if next slot in INPUT already has TOP_EXT\n            int next = ptr + 1;\n            if (next < other.length && other[next] == TOP_EXT) {\n              // Input already has TOP_EXT, copy it and skip ahead\n              arr[idx++] = TOP_EXT;\n              ptr++; // Skip the TOP_EXT in next iteration\n            } else {\n              // Input doesn't have TOP_EXT, add it\n              arr[idx++] = TOP_EXT;\n            }\n          }\n        }\n        stack = Arrays.copyOf(arr, idx);\n        stackPtr = idx;\n      } else {\n        reset();\n      }\n      maxStack = Math.max(stackPtr, maxStack);\n    }\n  }\n\n  static class LocalVarTypes {\n    private static final int DEFAULT_SIZE = 4;\n    private Object[] locals;\n    private int lastVarPtr = -1;\n    private int maxVarPtr = -1;\n\n    LocalVarTypes() {\n      locals = new Object[DEFAULT_SIZE];\n    }\n\n    LocalVarTypes(Object[] vals) {\n      replaceWith(vals);\n    }\n\n    public void resolveUnitializedThis(String typeName) {\n      for (int i = 0; i <= lastVarPtr; i++) {\n        if (locals[i] == UNINITIALIZED_THIS) {\n          locals[i] = typeName;\n        }\n      }\n    }\n    public void setType(int idx, Type t) {\n      int padding = t.getSize() - 1;\n      if ((idx + padding) >= locals.length) {\n        locals = Arrays.copyOf(locals, Math.round((idx + padding + 1) * 1.5f));\n      }\n      locals[idx] = toSlotType(t);\n      if (padding == 1) {\n        locals[idx + 1] = TOP_EXT;\n      }\n      setLastVarPtr(Math.max(idx + padding, lastVarPtr));\n    }\n\n    public Object getType(int idx) {\n      return idx < locals.length ? locals[idx] : null;\n    }\n\n    public final void replaceWith(Object[] other) {\n      Object[] arr = new Object[other.length * 2];\n      int idx = 0;\n      for (int i = 0; i < other.length; i++) {\n        Object o = other[i];\n        arr[idx++] = o;\n        if (o == LONG || o == DOUBLE) {\n          // Check if next slot in INPUT already has TOP_EXT\n          int lookup = i + 1;\n          if (lookup < other.length && other[lookup] == TOP_EXT) {\n            // Input already has TOP_EXT, copy it and skip ahead\n            arr[idx++] = TOP_EXT;\n            i++; // Skip the TOP_EXT in next iteration\n          } else {\n            // Input doesn't have TOP_EXT, add it\n            arr[idx++] = TOP_EXT;\n          }\n        }\n      }\n      locals = Arrays.copyOf(arr, idx);\n      setLastVarPtr(idx - 1);\n    }\n\n    public void mergeWith(Object[] other) {\n      Object[] arr = new Object[Math.max(other.length * 2, Math.max(lastVarPtr + 1, DEFAULT_SIZE))];\n      int idx = 0;\n      for (Object o : other) {\n        arr[idx++] = o == null ? TOP : o;\n      }\n      while (idx <= lastVarPtr) {\n        arr[idx++] = TOP;\n      }\n      locals = arr;\n      setLastVarPtr(idx - 1);\n    }\n\n    public Object[] toArray() {\n      return toArray(false);\n    }\n\n    public Object[] toArray(boolean compress) {\n      Object[] ret = new Object[size()];\n      int localCnt = 0;\n      for (int i = 0; i <= lastVarPtr; i++) {\n        Object o = locals[i];\n        if (o != null) {\n          if (compress && o == TOP_EXT) {\n            // When compressing for ASM API, skip TOP_EXT entirely.\n            // ASM's visitFrame() expects category-2 types (long/double) to be represented\n            // by a single element, NOT as [LONG, TOP] or [DOUBLE, TOP].\n            // See: ASM MethodVisitor API and JVMS Chapter 4\n            // - ASM API input: visitFrame(F_NEW, n, [Main, int, String, LONG, LONG], ...)\n            // - JVMS bytecode output: Disassembles to [Main, int, String, long, top, long, top]\n            // ASM handles the expansion from compact to JVMS format internally.\n            continue;\n          } else {\n            ret[localCnt++] = o;\n            // If this is a category-2 type, the next slot should be TOP_EXT (second half).\n            // Skip it to maintain compact ASM API format.\n            if (compress && (o == LONG || o == DOUBLE)) {\n              if (i + 1 <= lastVarPtr && locals[i + 1] == TOP_EXT) {\n                i++; // Skip the TOP_EXT in next iteration\n              }\n            }\n          }\n        } else {\n          ret[localCnt++] = TOP;\n        }\n      }\n      return Arrays.copyOf(ret, localCnt);\n    }\n\n    public void reset() {\n      locals = new Object[DEFAULT_SIZE];\n      setLastVarPtr(-1);\n    }\n\n    public int size() {\n      return lastVarPtr + 1;\n    }\n\n    public int maxSize() {\n      return maxVarPtr + 1;\n    }\n\n    public boolean isEmpty() {\n      return size() == 0;\n    }\n\n    private void setLastVarPtr(int ptr) {\n      lastVarPtr = ptr;\n      maxVarPtr = Math.max(lastVarPtr, maxVarPtr);\n    }\n  }\n\n  private static final class SavedState {\n    static final int CONDITIONAL = 0;\n    static final int UNCONDITIONAL = 1;\n    static final int EXCEPTION = 2;\n\n    private final LocalVarTypes lvTypes;\n    private final SimulatedStack sStack;\n    private final Collection<LocalVarSlot> newLocals;\n    private final int kind;\n\n    SavedState(\n        LocalVarTypes lvTypes,\n        SimulatedStack sStack,\n        Collection<LocalVarSlot> newLocals,\n        int kind) {\n      this.lvTypes = new LocalVarTypes(lvTypes.toArray());\n      this.sStack = new SimulatedStack(sStack.toArray());\n      this.newLocals = new HashSet<>(newLocals);\n      this.kind = kind;\n    }\n  }\n\n  static final class Introspection {\n    final SimulatedStack stack;\n    final LocalVarTypes lvTypes;\n    final Collection<LocalVarSlot> newLocals;\n    final Map<Label, SavedState> jumpTable;\n\n    private Introspection(InstrumentingMethodVisitor v) {\n      this.stack = new SimulatedStack(v.stack.toArray(false));\n      this.lvTypes = new LocalVarTypes(v.localTypes.toArray(false));\n      this.newLocals = new HashSet<>(v.newLocals);\n      this.jumpTable = new HashMap<>(v.jumpTargetStates);\n    }\n  }\n\n  Introspection introspect() {\n    return new Introspection(this);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/Instrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport java.lang.invoke.CallSite;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.MethodType;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.regex.PatternSyntaxException;\nimport org.objectweb.asm.AnnotationVisitor;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.Handle;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\nimport org.openjdk.btrace.core.MethodID;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/**\n * This instruments a probed class with BTrace probe action class.\n *\n * @author A. Sundararajan\n */\npublic class Instrumentor extends ClassVisitor {\n  private final BTraceProbe bcn;\n  private final ClassLoader cl;\n  private final Collection<OnMethod> applicableOnMethods;\n  private final Set<OnMethod> calledOnMethods = new HashSet<>();\n\n  private String className, superName;\n\n  private Instrumentor(\n      ClassLoader cl, BTraceProbe bcn, Collection<OnMethod> applicables, ClassVisitor cv) {\n    super(ASM9, cv);\n    this.cl = cl;\n    this.bcn = bcn;\n    applicableOnMethods = applicables;\n  }\n\n  static final Instrumentor create(\n      BTraceClassReader cr, BTraceProbe bcn, ClassVisitor cv, ClassLoader cl) {\n    if (cr.isInterface()) {\n      // do not instrument interfaces\n      return null;\n    }\n\n    Collection<OnMethod> applicables = bcn.getApplicableHandlers(cr);\n    if (applicables != null && !applicables.isEmpty()) {\n      return new Instrumentor(cl, bcn, applicables, cv);\n    }\n    return null;\n  }\n\n  private static String getLevelStrSafe(OnMethod om) {\n    return om.getLevel() != null ? om.getLevel().getValue().toString() : \"\";\n  }\n\n  private static void reportPatternSyntaxException(String pattern) {\n    System.err.println(\"btrace ERROR: invalid regex pattern - \" + pattern);\n  }\n\n  public final boolean hasMatch() {\n    return !calledOnMethods.isEmpty();\n  }\n\n  @Override\n  public void visit(\n      int version,\n      int access,\n      String name,\n      String signature,\n      String superName,\n      String[] interfaces) {\n    className = name;\n    this.superName = superName;\n    super.visit(Math.max(Opcodes.V1_7, version), access, name, signature, superName, interfaces);\n  }\n\n  @Override\n  public MethodVisitor visitMethod(\n      int access, String name, String desc, String signature, String[] exceptions) {\n\n    // Skip weaving into sensitive methods even if class matched by probes\n    if (ClassFilter.isSensitiveMethod(className, name, desc)) {\n      return super.visitMethod(access, name, desc, signature, exceptions);\n    }\n\n    List<OnMethod> appliedOnMethods = new ArrayList<>();\n\n    if (applicableOnMethods.isEmpty()\n        || (access & ACC_ABSTRACT) != 0\n        || name.startsWith(Constants.BTRACE_METHOD_PREFIX)) {\n      return super.visitMethod(access, name, desc, signature, exceptions);\n    }\n\n    Set<OnMethod> annotationMatchers = new HashSet<>();\n\n    for (OnMethod om : applicableOnMethods) {\n      if (om.getLocation().getValue() == Kind.LINE) {\n        appliedOnMethods.add(om);\n      } else {\n        if (om.isMethodAnnotationMatcher()) {\n          annotationMatchers.add(om);\n          continue;\n        }\n        String methodName = om.getMethod();\n        boolean regexMatch = om.isMethodRegexMatcher();\n        if (methodName.isEmpty()) {\n          methodName = \".*\"; // match all the methods\n          regexMatch = true;\n        }\n        if (methodName.equals(\"#\")) {\n          methodName = om.getTargetName(); // match just the same-named method\n        }\n\n        if (methodName.equals(name) && typeMatches(om.getType(), desc, om.isExactTypeMatch())) {\n          appliedOnMethods.add(om);\n        } else if (regexMatch) {\n          try {\n            if (name.matches(methodName)\n                && typeMatches(om.getType(), desc, om.isExactTypeMatch())) {\n              appliedOnMethods.add(om);\n            }\n          } catch (PatternSyntaxException pse) {\n            reportPatternSyntaxException(name);\n          }\n        }\n      }\n    }\n\n    if (annotationMatchers.isEmpty() && appliedOnMethods.isEmpty()) {\n      return super.visitMethod(access, name, desc, signature, exceptions);\n    }\n\n    MethodVisitor methodVisitor;\n\n    methodVisitor = super.visitMethod(access, name, desc, signature, exceptions);\n\n    InstrumentingMethodVisitor mHelper =\n        new InstrumentingMethodVisitor(access, className, name, desc, methodVisitor);\n\n    // Count handlers with level checks to determine if caching is needed\n    long levelCheckCount =\n        appliedOnMethods.stream()\n            .filter(\n                om -> {\n                  String levelStr = getLevelStrSafe(om);\n                  return levelStr != null && !levelStr.isEmpty();\n                })\n            .count();\n    // Also count annotation matchers with level checks\n    long annotationMatcherLevelCount =\n        annotationMatchers.stream()\n            .filter(\n                om -> {\n                  String levelStr = getLevelStrSafe(om);\n                  return levelStr != null && !levelStr.isEmpty();\n                })\n            .count();\n    mHelper.setShouldCacheLevelVar((levelCheckCount + annotationMatcherLevelCount) > 1);\n\n    methodVisitor = mHelper;\n\n    for (OnMethod om : appliedOnMethods) {\n      methodVisitor = instrumentorFor(om, methodVisitor, mHelper, access, name, desc);\n    }\n\n    return new MethodVisitor(ASM9, methodVisitor) {\n      @Override\n      public AnnotationVisitor visitAnnotation(String annoDesc, boolean visible) {\n        for (OnMethod om : annotationMatchers) {\n          String extAnnoName = Type.getType(annoDesc).getClassName();\n          String annoName = om.getMethod();\n          if (om.isMethodRegexMatcher()) {\n            try {\n              if (extAnnoName.matches(annoName)) {\n                mv = instrumentorFor(om, mv, mHelper, access, name, desc);\n              }\n            } catch (PatternSyntaxException pse) {\n              reportPatternSyntaxException(extAnnoName);\n            }\n          } else if (annoName.equals(extAnnoName)) {\n            mv = instrumentorFor(om, mv, mHelper, access, name, desc);\n          }\n        }\n        return mv.visitAnnotation(annoDesc, visible);\n      }\n    };\n  }\n\n  private String getMethodOrFieldName(\n      boolean fqn, int opcode, String owner, String name, String desc) {\n    StringBuilder mName = new StringBuilder();\n    if (fqn) {\n      switch (opcode) {\n        case INVOKEDYNAMIC:\n          {\n            mName.append(\"dynamic\");\n            break;\n          }\n        case INVOKEINTERFACE:\n          {\n            mName.append(\"interface\");\n            break;\n          }\n        case INVOKESPECIAL:\n          {\n            mName.append(\"special\");\n            break;\n          }\n        case INVOKESTATIC:\n          {\n            mName.append(\"static\");\n            break;\n          }\n        case INVOKEVIRTUAL:\n          {\n            mName.append(\"virtual\");\n            break;\n          }\n        case PUTSTATIC:\n        case GETSTATIC:\n          {\n            mName.append(\"static field\");\n            break;\n          }\n        case PUTFIELD:\n        case GETFIELD:\n          {\n            mName.append(\"field\");\n            break;\n          }\n      }\n      mName.append(' ');\n      mName.append(TypeUtils.descriptorToSimplified(desc, owner, name));\n    } else {\n      mName.append(name);\n    }\n    return mName.toString();\n  }\n\n  private MethodVisitor instrumentorFor(\n      OnMethod om,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      int access,\n      String name,\n      String desc) {\n    Location loc = om.getLocation();\n    Where where = loc.getWhere();\n    Type[] actionArgTypes = Type.getArgumentTypes(om.getTargetDescriptor());\n    int numActionArgs = actionArgTypes.length;\n\n    switch (loc.getValue()) {\n      case ARRAY_GET:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"Array Get Instrumentor\">\n        return new ArrayAccessInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n          private final int INDEX_PTR = 0;\n          private final int INSTANCE_PTR = 1;\n          final int[] argsIndex = {Integer.MIN_VALUE, Integer.MIN_VALUE};\n\n          @Override\n          protected void onBeforeArrayLoad(int opcode) {\n            Type arrtype = TypeUtils.getArrayType(opcode);\n            Type retType = TypeUtils.getElementType(opcode);\n\n            if (locationTypeMismatch(loc, arrtype, retType)) return;\n\n            addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n            addExtraTypeInfo(om.getTargetInstanceParameter(), arrtype);\n\n            if (where == Where.AFTER) {\n              addExtraTypeInfo(om.getReturnParameter(), retType);\n            }\n            ValidationResult vr = validateArguments(om, actionArgTypes, new Type[] {Type.INT_TYPE});\n            if (vr.isValid()) {\n              if (!vr.isAny()) {\n                asm.dup2();\n                argsIndex[INDEX_PTR] = storeAsNew();\n                argsIndex[INSTANCE_PTR] = storeAsNew();\n              }\n              Label l = levelCheckBefore(om, bcn.getClassName(true));\n              if (where == Where.BEFORE) {\n                Label l1 = asm.openLinkerCheck();\n\n                loadArguments(\n                    localVarArg(vr.getArgIdx(INDEX_PTR), Type.INT_TYPE, argsIndex[INDEX_PTR]),\n                    localVarArg(\n                        om.getTargetInstanceParameter(),\n                        Constants.OBJECT_TYPE,\n                        argsIndex[INSTANCE_PTR]),\n                    constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                    constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                    selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n                invokeBTraceAction(asm, om);\n                asm.closeLinkerCheck(l1);\n              }\n              if (l != null) {\n                mv.visitLabel(l);\n                insertFrameSameStack(l);\n              }\n            }\n          }\n\n          @Override\n          protected void onAfterArrayLoad(int opcode) {\n            if (where == Where.AFTER) {\n              Type arrtype = TypeUtils.getArrayType(opcode);\n              Type retType = TypeUtils.getElementType(opcode);\n\n              if (locationTypeMismatch(loc, arrtype, retType)) return;\n\n              addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n              addExtraTypeInfo(om.getTargetInstanceParameter(), arrtype);\n              addExtraTypeInfo(om.getReturnParameter(), retType);\n              ValidationResult vr =\n                  validateArguments(om, actionArgTypes, new Type[] {Type.INT_TYPE});\n              if (vr.isValid()) {\n                Label l = levelCheckAfter(om, bcn.getClassName(true));\n\n                int retValIndex = -1;\n                Type actionArgRetType =\n                    om.getReturnParameter() != -1\n                        ? actionArgTypes[om.getReturnParameter()]\n                        : Type.VOID_TYPE;\n                if (om.getReturnParameter() != -1) {\n                  asm.dupArrayValue(opcode);\n                  retValIndex = storeNewLocal(retType);\n                }\n\n                Label l1 = asm.openLinkerCheck();\n\n                loadArguments(\n                    localVarArg(vr.getArgIdx(INDEX_PTR), Type.INT_TYPE, argsIndex[INDEX_PTR]),\n                    localVarArg(\n                        om.getTargetInstanceParameter(),\n                        Constants.OBJECT_TYPE,\n                        argsIndex[INSTANCE_PTR]),\n                    constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                    constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                    localVarArg(\n                        om.getReturnParameter(),\n                        retType,\n                        retValIndex,\n                        TypeUtils.isAnyType(actionArgRetType)),\n                    selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n                invokeBTraceAction(asm, om);\n\n                asm.closeLinkerCheck(l1);\n\n                if (l != null) {\n                  mv.visitLabel(l);\n                  insertFrameSameStack(l);\n                }\n              }\n            }\n          }\n        }; // </editor-fold>\n\n      case ARRAY_SET:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"Array Set Instrumentor\">\n        return new ArrayAccessInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n          private final int INDEX_PTR = 0, VALUE_PTR = 1, INSTANCE_PTR = 2;\n          final int[] argsIndex = {-1, -1, -1, -1};\n\n          @Override\n          protected void onBeforeArrayStore(int opcode) {\n            Type elementType = TypeUtils.getElementType(opcode);\n            Type arrayType = TypeUtils.getArrayType(opcode);\n\n            if (locationTypeMismatch(loc, arrayType, elementType)) return;\n\n            addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n            addExtraTypeInfo(om.getTargetInstanceParameter(), arrayType);\n\n            ValidationResult vr =\n                validateArguments(om, actionArgTypes, new Type[] {Type.INT_TYPE, elementType});\n            if (vr.isValid()) {\n              Type argElementType = Type.VOID_TYPE;\n\n              if (!vr.isAny()) {\n                int elementIdx = vr.getArgIdx(VALUE_PTR);\n                argElementType = elementIdx > -1 ? actionArgTypes[elementIdx] : Type.VOID_TYPE;\n                argsIndex[VALUE_PTR] = storeAsNew();\n                asm.dup2();\n                argsIndex[INDEX_PTR] = storeAsNew();\n                argsIndex[INSTANCE_PTR] = storeAsNew();\n                asm.loadLocal(elementType, argsIndex[VALUE_PTR]);\n              }\n\n              Label l = levelCheckBefore(om, bcn.getClassName(true));\n\n              if (where == Where.BEFORE) {\n                Label l1 = asm.openLinkerCheck();\n\n                loadArguments(\n                    localVarArg(\n                        om.getTargetInstanceParameter(), arrayType, argsIndex[INSTANCE_PTR]),\n                    localVarArg(vr.getArgIdx(INDEX_PTR), Type.INT_TYPE, argsIndex[INDEX_PTR]),\n                    localVarArg(\n                        vr.getArgIdx(VALUE_PTR),\n                        elementType,\n                        argsIndex[VALUE_PTR],\n                        TypeUtils.isAnyType(argElementType)),\n                    constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                    constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                    selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n                invokeBTraceAction(asm, om);\n\n                asm.closeLinkerCheck(l1);\n              }\n              if (l != null) {\n                mv.visitLabel(l);\n                insertFrameSameStack(l);\n              }\n            }\n          }\n\n          @Override\n          protected void onAfterArrayStore(int opcode) {\n            if (where == Where.AFTER) {\n              Type elementType = TypeUtils.getElementType(opcode);\n              Type arrayType = TypeUtils.getArrayType(opcode);\n\n              if (locationTypeMismatch(loc, arrayType, elementType)) return;\n\n              addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n              addExtraTypeInfo(om.getTargetInstanceParameter(), arrayType);\n\n              ValidationResult vr =\n                  validateArguments(om, actionArgTypes, new Type[] {Type.INT_TYPE, elementType});\n              if (vr.isValid()) {\n                int elementIdx = vr.getArgIdx(VALUE_PTR);\n                Type argElementType = elementIdx > -1 ? actionArgTypes[elementIdx] : Type.VOID_TYPE;\n\n                Label l = levelCheckAfter(om, bcn.getClassName(true));\n                Label l1 = asm.openLinkerCheck();\n\n                loadArguments(\n                    localVarArg(\n                        om.getTargetInstanceParameter(), arrayType, argsIndex[INSTANCE_PTR]),\n                    localVarArg(vr.getArgIdx(INDEX_PTR), Type.INT_TYPE, argsIndex[INDEX_PTR]),\n                    localVarArg(\n                        vr.getArgIdx(VALUE_PTR),\n                        elementType,\n                        argsIndex[VALUE_PTR],\n                        TypeUtils.isAnyType(argElementType)),\n                    constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                    constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                    isStatic()\n                        ? constArg(om.getSelfParameter(), null)\n                        : localVarArg(om.getSelfParameter(), Type.getObjectType(className), 0));\n\n                invokeBTraceAction(asm, om);\n                asm.closeLinkerCheck(l1);\n                if (l != null) {\n                  mv.visitLabel(l);\n                  insertFrameSameStack(l);\n                }\n              }\n            }\n          }\n        }; // </editor-fold>\n\n      case CALL:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"Method Call Instrumentor\">\n        return new MethodCallInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n\n          private final String localClassName = loc.getClazz();\n          private final String localMethodName = loc.getMethod();\n          int[] backupArgsIndices;\n          private int returnVarIndex = -1;\n          private boolean generatingCode = false;\n          private MethodTrackingContext trackingCtx;\n\n          private void injectBtrace(\n              ValidationResult vr,\n              String method,\n              Type[] callArgTypes,\n              Type returnType,\n              boolean staticCall) {\n            ArgumentProvider[] actionArgs = new ArgumentProvider[actionArgTypes.length + 7];\n            for (int i = 0; i < vr.getArgCnt(); i++) {\n              int index = vr.getArgIdx(i);\n              Type t = actionArgTypes[index];\n              if (TypeUtils.isAnyTypeArray(t)) {\n                if (i < backupArgsIndices.length - 1) {\n                  actionArgs[i] = anytypeArg(index, backupArgsIndices[i + 1], callArgTypes);\n                } else {\n                  actionArgs[i] =\n                      new ArgumentProvider(asm, index) {\n\n                        @Override\n                        protected void doProvide() {\n                          asm.push(0).newArray(Constants.OBJECT_TYPE);\n                        }\n                      };\n                }\n              } else {\n                actionArgs[i] = localVarArg(index, actionArgTypes[index], backupArgsIndices[i + 1]);\n              }\n            }\n            actionArgs[actionArgTypes.length] =\n                localVarArg(om.getReturnParameter(), returnType, returnVarIndex);\n            actionArgs[actionArgTypes.length + 1] =\n                staticCall\n                    ? constArg(om.getTargetInstanceParameter(), null)\n                    : localVarArg(\n                        om.getTargetInstanceParameter(),\n                        Constants.OBJECT_TYPE,\n                        backupArgsIndices.length == 0 ? -1 : backupArgsIndices[0]);\n            actionArgs[actionArgTypes.length + 2] =\n                constArg(om.getTargetMethodOrFieldParameter(), method);\n            actionArgs[actionArgTypes.length + 3] =\n                constArg(om.getClassNameParameter(), className.replace('/', '.'));\n            actionArgs[actionArgTypes.length + 4] =\n                constArg(om.getMethodParameter(), getName(om.isMethodFqn()));\n            actionArgs[actionArgTypes.length + 5] =\n                selfArg(om.getSelfParameter(), Type.getObjectType(className));\n            actionArgs[actionArgTypes.length + 6] =\n                new ArgumentProvider(asm, om.getDurationParameter()) {\n                  @Override\n                  public void doProvide() {\n                    if (trackingCtx != null) {\n                      trackingCtx.emitDuration();\n                    }\n                  }\n                };\n\n            loadArguments(actionArgs);\n\n            invokeBTraceAction(asm, om);\n          }\n\n          @Override\n          protected void onBeforeCallMethod(int opcode, String cOwner, String cName, String cDesc) {\n            if (!generatingCode) {\n              try {\n                generatingCode = true;\n                if (matches(localClassName, cOwner.replace('/', '.'))\n                        && matches(localMethodName, cName)\n                        && typeMatches(loc.getType(), cDesc, om.isExactTypeMatch())) {\n\n                  /*\n                   * Generate a synthetic method id for the method call.\n                   * It will be different from the 'native' method id\n                   * in order to prevent double accounting for one hit.\n                   */\n                  int parentMid = MethodID.getMethodId(className, name, desc);\n                  int mid = MethodID.getMethodId(\"c$\" + parentMid + \"$\" + cOwner, cName, cDesc);\n\n                  String method =\n                          getMethodOrFieldName(om.isTargetMethodOrFieldFqn(), opcode, cOwner, cName, cDesc);\n                  Type[] calledMethodArgs = Type.getArgumentTypes(cDesc);\n                  addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n                  addExtraTypeInfo(om.getTargetInstanceParameter(), Type.getObjectType(cOwner));\n                  if (where == Where.AFTER) {\n                    addExtraTypeInfo(om.getReturnParameter(), Type.getReturnType(cDesc));\n                  }\n                  ValidationResult vr = validateArguments(om, actionArgTypes, calledMethodArgs);\n                  if (vr.isValid()) {\n                    boolean isStaticCall = (opcode == INVOKESTATIC);\n                    if (!isStaticCall) {\n                      if (where == Where.BEFORE && cName.equals(Constants.CONSTRUCTOR)) {\n                        return;\n                      }\n                    }\n\n                    trackingCtx = new MethodTrackingContext(mv, asm, mHelper, bcn.getClassName(true), mid);\n                    if (om.getDurationParameter() != -1) {\n                      trackingCtx.emitEntry(true, om.getSamplerKind(), om.getSamplerMean(), mid, getLevelStrSafe(om));\n                    } else {\n                      trackingCtx.emitEntry(false, om.getSamplerKind(), om.getSamplerMean(), mid, getLevelStrSafe(om));\n                    }\n\n                    Type[] argTypes = Type.getArgumentTypes(cDesc);\n                    boolean shouldBackup = !vr.isAny() || om.getTargetInstanceParameter() != -1;\n\n                    // will store the call args into local variables\n                    backupArgsIndices = shouldBackup ? backupStack(argTypes, isStaticCall) : new int[0];\n\n                    if (where == Where.BEFORE) {\n                      trackingCtx.emitTestSample(false, mid);\n                      Label l = levelCheckBefore(om, bcn.getClassName(true));\n\n                      Label l1 = asm.openLinkerCheck();\n\n                      injectBtrace(vr, method, argTypes, Type.getReturnType(cDesc), isStaticCall);\n\n                      asm.closeLinkerCheck(l1);\n                      if (l != null) {\n                        mv.visitLabel(l);\n                        insertFrameSameStack(l);\n                      }\n                      trackingCtx.emitElse();\n                    }\n\n                    // put the call args back on stack so the method call can find them\n                    if (shouldBackup) {\n                      restoreStack(backupArgsIndices, argTypes, isStaticCall);\n                    }\n                  }\n                }\n              } finally {\n                generatingCode = false;\n              }\n            }\n          }\n\n          @Override\n          protected void onAfterCallMethod(int opcode, String cOwner, String cName, String cDesc) {\n            if (matches(localClassName, cOwner.replace('/', '.'))\n                && matches(localMethodName, cName)\n                && typeMatches(loc.getType(), cDesc, om.isExactTypeMatch())) {\n\n              int parentMid = MethodID.getMethodId(className, name, desc);\n              int mid = MethodID.getMethodId(\"c$\" + parentMid + \"$\" + cOwner, cName, cDesc);\n\n              Type returnType = Type.getReturnType(cDesc);\n              Type[] calledMethodArgs = Type.getArgumentTypes(cDesc);\n              addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n              addExtraTypeInfo(om.getTargetInstanceParameter(), Type.getObjectType(cOwner));\n              addExtraTypeInfo(om.getReturnParameter(), returnType);\n              ValidationResult vr = validateArguments(om, actionArgTypes, calledMethodArgs);\n              if (vr.isValid()) {\n                MethodTrackingContext trackingCtx = new MethodTrackingContext(mv, asm, mHelper, bcn.getClassName(true), mid);\n                if (om.getDurationParameter() == -1) {\n                  trackingCtx.emitExit(mid);\n                }\n                if (where == Where.AFTER) {\n                  if (om.getDurationParameter() != -1) {\n                    trackingCtx.emitTestSample(true, mid);\n                  } else {\n                    trackingCtx.emitTestSample(false, mid);\n                  }\n\n                  Label l = levelCheckAfter(om, bcn.getClassName(true));\n\n                  String method =\n                      getMethodOrFieldName(\n                          om.isTargetMethodOrFieldFqn(), opcode, cOwner, cName, cDesc);\n                  boolean withReturn =\n                      om.getReturnParameter() != -1 && !returnType.equals(Type.VOID_TYPE);\n\n                  Label l1 = asm.openLinkerCheck();\n                  if (withReturn) {\n                    // store the return value to a local variable if not augmented return\n                    if (Type.getReturnType(om.getTargetDescriptor()).getSort() == Type.VOID) {\n                      asm.dupValue(returnType);\n                    }\n                    returnVarIndex = storeAsNew();\n                  }\n                  // will also retrieve the call args and the return value from the backup variables\n                  injectBtrace(vr, method, calledMethodArgs, returnType, opcode == INVOKESTATIC);\n\n                  asm.closeLinkerCheck(l1);\n                  if (l != null) {\n                    mv.visitLabel(l);\n                    insertFrameSameStack(l);\n                  }\n\n                  trackingCtx.emitElse();\n\n                  if (parent == null) {\n                    trackingCtx.reset();\n                  }\n                }\n              }\n            }\n          }\n        }; // </editor-fold>\n\n      case CATCH:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"Catch Instrumentor\">\n        return new CatchInstrumentor(cl, mv, mHelper, className, superName, access, name, desc) {\n          @Override\n          protected void onCatch(String type) {\n            Type exctype = Type.getObjectType(type);\n            addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n            addExtraTypeInfo(om.getTargetInstanceParameter(), exctype);\n            ValidationResult vr =\n                validateArguments(om, actionArgTypes, Type.getArgumentTypes(getDescriptor()));\n            if (vr.isValid()) {\n              int index = -1;\n              Label l = levelCheck(om, bcn.getClassName(true));\n\n              if (om.getTargetInstanceParameter() != -1) {\n                asm.dup();\n                index = storeAsNew();\n              }\n              Label l1 = asm.openLinkerCheck();\n\n              loadArguments(\n                  localVarArg(om.getTargetInstanceParameter(), exctype, index),\n                  constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                  constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                  selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n              invokeBTraceAction(asm, om);\n\n              asm.closeLinkerCheck(l1);\n\n              if (l != null) {\n                mv.visitLabel(l);\n                insertFrameSameStack(l);\n              }\n            }\n          }\n        }; // </editor-fold>\n\n      case CHECKCAST:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"CheckCast Instrumentor\">\n        return new TypeCheckInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n\n          private void callAction(int opcode, String desc) {\n            if (opcode == CHECKCAST) {\n              Type castType = Type.getObjectType(desc);\n              addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n              addExtraTypeInfo(om.getTargetInstanceParameter(), Constants.OBJECT_TYPE);\n              ValidationResult vr =\n                  validateArguments(om, actionArgTypes, new Type[] {Constants.STRING_TYPE});\n              if (vr.isValid()) {\n                int castTypeIndex = -1;\n                Label l = levelCheck(om, bcn.getClassName(true));\n\n                if (!vr.isAny()) {\n                  asm.dup();\n                  castTypeIndex = storeAsNew();\n                }\n\n                Label l1 = asm.openLinkerCheck();\n\n                loadArguments(\n                    constArg(vr.getArgIdx(0), castType.getClassName()),\n                    constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                    constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                    selfArg(om.getSelfParameter(), Type.getObjectType(className)),\n                    localVarArg(\n                        om.getTargetInstanceParameter(), Constants.OBJECT_TYPE, castTypeIndex));\n\n                invokeBTraceAction(asm, om);\n\n                asm.closeLinkerCheck(l1);\n\n                if (l != null) {\n                  mv.visitLabel(l);\n                  insertFrameSameStack(l);\n                }\n              }\n            }\n          }\n\n          @Override\n          protected void onBeforeTypeCheck(int opcode, String desc) {\n            if (where == Where.BEFORE) {\n              callAction(opcode, desc);\n            }\n          }\n\n          @Override\n          protected void onAfterTypeCheck(int opcode, String desc) {\n            if (where == Where.AFTER) {\n              callAction(opcode, desc);\n            }\n          }\n        }; // </editor-fold>\n\n      case ENTRY:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"Method Entry Instrumentor\">\n        return new MethodReturnInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n          private final ValidationResult vr;\n          private MethodTrackingContext trackingCtx;\n\n          {\n            Type[] calledMethodArgs = Type.getArgumentTypes(getDescriptor());\n            addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n            vr = validateArguments(om, actionArgTypes, calledMethodArgs);\n            int mid = MethodID.getMethodId(className, name, desc);\n            trackingCtx =\n                mHelper.getOrCreateTrackingContext(\n                    mid,\n                    () -> new MethodTrackingContext(mv, asm, mHelper, bcn.getClassName(true), mid));\n          }\n\n          private void injectBtrace() {\n            Label l1 = asm.openLinkerCheck();\n\n            if (numActionArgs > 0) {\n              loadArguments(\n                      vr,\n                      actionArgTypes,\n                      isStatic(),\n                      constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                      constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                      selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n            }\n            invokeBTraceAction(asm, om);\n            asm.closeLinkerCheck(l1);\n          }\n\n          @Override\n          protected void visitMethodPrologue() {\n            if (vr.isValid() || vr.isAny()) {\n              if (om.getSamplerKind() != Sampled.Sampler.None) {\n                int mid = MethodID.getMethodId(className, name, desc);\n                trackingCtx.emitEntry(false, om.getSamplerKind(), om.getSamplerMean(), mid, getLevelStrSafe(om));\n              }\n            }\n            super.visitMethodPrologue();\n          }\n\n          @Override\n          protected void onMethodEntry() {\n            if (vr.isValid() || vr.isAny()) {\n              if (om.getSamplerKind() != Sampled.Sampler.None) {\n                int mid = MethodID.getMethodId(className, name, desc);\n                trackingCtx.emitTestSample(true, mid);\n              }\n              injectBtrace();\n              if (om.getSamplerKind() != Sampled.Sampler.None) {\n                trackingCtx.emitElse();\n              }\n            }\n          }\n\n          @Override\n          protected void onMethodReturn(int opcode) {\n            if (vr.isValid() || vr.isAny()) {\n              if (om.getSamplerKind() == Sampled.Sampler.Adaptive) {\n                int mid = MethodID.getMethodId(className, name, desc);\n                trackingCtx.emitExit(mid);\n              }\n            }\n          }\n        }; // </editor-fold>\n\n      case ERROR:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"Error Instrumentor\">\n        return new ErrorReturnInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n          final ValidationResult vr;\n          private boolean generatingCode = false;\n          private MethodTrackingContext trackingCtx;\n\n          {\n            addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n            addExtraTypeInfo(om.getTargetInstanceParameter(), Constants.THROWABLE_TYPE);\n            vr = validateArguments(om, actionArgTypes, Type.getArgumentTypes(getDescriptor()));\n            int mid = MethodID.getMethodId(className, name, desc);\n            trackingCtx =\n                mHelper.getOrCreateTrackingContext(\n                    mid,\n                    () -> new MethodTrackingContext(mv, asm, mHelper, bcn.getClassName(true), mid));\n          }\n\n          @Override\n          protected void onErrorReturn() {\n            if (vr.isValid()) {\n              int throwableIndex = -1;\n              int mid = MethodID.getMethodId(className, name, desc);\n\n              // For error handlers with duration, compute duration directly without sampling/level checks\n              if (om.getDurationParameter() != -1) {\n                trackingCtx.resetDuration();\n                trackingCtx.computeDurationForErrorHandler();\n              }\n\n              if (om.getTargetInstanceParameter() != -1) {\n                asm.dup();\n                throwableIndex = storeAsNew();\n              }\n\n              ArgumentProvider[] actionArgs = new ArgumentProvider[5];\n\n              actionArgs[0] =\n                  localVarArg(\n                      om.getTargetInstanceParameter(), Constants.THROWABLE_TYPE, throwableIndex);\n              actionArgs[1] = constArg(om.getClassNameParameter(), className.replace('/', '.'));\n              actionArgs[2] = constArg(om.getMethodParameter(), getName(om.isMethodFqn()));\n              actionArgs[3] = selfArg(om.getSelfParameter(), Type.getObjectType(className));\n              actionArgs[4] =\n                  new ArgumentProvider(asm, om.getDurationParameter()) {\n                    @Override\n                    public void doProvide() {\n                      if (trackingCtx != null) {\n                        trackingCtx.emitDuration();\n                      }\n                    }\n                  };\n\n              Label l1 = asm.openLinkerCheck();\n\n              loadArguments(vr, actionArgTypes, isStatic(), actionArgs);\n\n              invokeBTraceAction(asm, om);\n\n              asm.closeLinkerCheck(l1);\n            }\n          }\n\n          @Override\n          protected void visitMethodPrologue() {\n            if (vr.isValid()) {\n              if (!generatingCode) {\n                try {\n                  generatingCode = true;\n                  int mid = MethodID.getMethodId(className, name, desc);\n                  if (om.getDurationParameter() != -1) {\n                    trackingCtx.emitEntry(true, om.getSamplerKind(), om.getSamplerMean(), mid, getLevelStrSafe(om));\n                  } else {\n                    trackingCtx.emitEntry(false, om.getSamplerKind(), om.getSamplerMean(), mid, getLevelStrSafe(om));\n                  }\n                } finally {\n                  generatingCode = false;\n                }\n              }\n            }\n            super.visitMethodPrologue();\n          }\n        };\n        // </editor-fold>\n\n      case FIELD_GET:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"Field Get Instrumentor\">\n        return new FieldAccessInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n\n          private final String targetClassName = loc.getClazz();\n          private final String targetFieldName = loc.getField();\n          int calledInstanceIndex = Integer.MIN_VALUE;\n\n          @Override\n          protected void onBeforeGetField(int opcode, String owner, String name, String desc) {\n            if (matches(targetClassName, owner.replace('/', '.'))\n                && matches(targetFieldName, name)) {\n\n              Type fldType = Type.getType(desc);\n              addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n              addExtraTypeInfo(om.getTargetInstanceParameter(), Type.getObjectType(owner));\n              if (where == Where.AFTER) {\n                addExtraTypeInfo(om.getReturnParameter(), fldType);\n              }\n              ValidationResult vr = validateArguments(om, actionArgTypes, new Type[0]);\n              if (vr.isValid()) {\n                if (!isStaticAccess && om.getTargetInstanceParameter() != -1) {\n                  asm.dup();\n                  calledInstanceIndex = storeAsNew();\n                }\n\n                Label l = levelCheckBefore(om, bcn.getClassName(true));\n\n                if (where == Where.BEFORE) {\n                  Label l1 = asm.openLinkerCheck();\n\n                  loadArguments(\n                      isStaticAccess\n                          ? constArg(om.getTargetInstanceParameter(), null)\n                          : localVarArg(\n                              om.getTargetInstanceParameter(),\n                              Constants.OBJECT_TYPE,\n                              calledInstanceIndex),\n                      constArg(\n                          om.getTargetMethodOrFieldParameter(),\n                          getMethodOrFieldName(\n                              om.isTargetMethodOrFieldFqn(),\n                              opcode,\n                              owner,\n                              name,\n                              desc)),\n                      constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                      constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                      selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n                  invokeBTraceAction(asm, om);\n                  asm.closeLinkerCheck(l1);\n                }\n                if (l != null) {\n                  mv.visitLabel(l);\n                  insertFrameSameStack(l);\n                }\n              }\n            }\n          }\n\n          @Override\n          protected void onAfterGetField(int opcode, String owner, String name, String desc) {\n            if (where == Where.AFTER\n                && matches(targetClassName, owner.replace('/', '.'))\n                && matches(targetFieldName, name)) {\n              Type fldType = Type.getType(desc);\n\n              addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n              addExtraTypeInfo(om.getTargetInstanceParameter(), Type.getObjectType(owner));\n              addExtraTypeInfo(om.getReturnParameter(), fldType);\n              ValidationResult vr = validateArguments(om, actionArgTypes, new Type[0]);\n              if (vr.isValid()) {\n                int returnValIndex = -1;\n                Label l = levelCheckAfter(om, bcn.getClassName(true));\n\n                if (om.getReturnParameter() != -1) {\n                  asm.dupValue(desc);\n                  returnValIndex = storeAsNew();\n                }\n\n                Label l1 = asm.openLinkerCheck();\n                loadArguments(\n                    isStaticAccess\n                        ? constArg(om.getTargetInstanceParameter(), null)\n                        : localVarArg(\n                            om.getTargetInstanceParameter(),\n                            Constants.OBJECT_TYPE,\n                            calledInstanceIndex),\n                    constArg(\n                        om.getTargetMethodOrFieldParameter(),\n                        getMethodOrFieldName(\n                            om.isTargetMethodOrFieldFqn(),\n                            opcode,\n                            owner,\n                            name,\n                            desc)),\n                    localVarArg(om.getReturnParameter(), fldType, returnValIndex),\n                    constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                    constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                    selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n                invokeBTraceAction(asm, om);\n                asm.closeLinkerCheck(l1);\n                if (l != null) {\n                  mv.visitLabel(l);\n                  insertFrameSameStack(l);\n                }\n              }\n            }\n          }\n        }; // </editor-fold>\n\n      case FIELD_SET:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"Field Set Instrumentor\">\n        return new FieldAccessInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n          private final String targetClassName = loc.getClazz();\n          private final String targetFieldName = loc.getField();\n          private int calledInstanceIndex = Integer.MIN_VALUE;\n          private int fldValueIndex = -1;\n\n          @Override\n          protected void onBeforePutField(int opcode, String owner, String name, String desc) {\n            if (matches(targetClassName, owner.replace('/', '.'))\n                && matches(targetFieldName, name)) {\n\n              Type fieldType = Type.getType(desc);\n\n              addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n              addExtraTypeInfo(om.getTargetInstanceParameter(), Type.getObjectType(owner));\n              ValidationResult vr = validateArguments(om, actionArgTypes, new Type[] {fieldType});\n\n              if (vr.isValid()) {\n                if (!vr.isAny()) {\n                  // store the field value\n                  fldValueIndex = storeAsNew();\n                }\n\n                if (!isStaticAccess && om.getTargetInstanceParameter() != -1) {\n                  asm.dup();\n                  calledInstanceIndex = storeAsNew();\n                }\n\n                if (!vr.isAny()) {\n                  // need to put the set value back on stack\n                  asm.loadLocal(fieldType, fldValueIndex);\n                }\n\n                Label l = levelCheckBefore(om, bcn.getClassName(true));\n\n                if (where == Where.BEFORE) {\n                  Label l1 = asm.openLinkerCheck();\n                  loadArguments(\n                      localVarArg(vr.getArgIdx(0), fieldType, fldValueIndex),\n                      isStaticAccess\n                          ? constArg(om.getTargetInstanceParameter(), null)\n                          : localVarArg(\n                              om.getTargetInstanceParameter(),\n                              Constants.OBJECT_TYPE,\n                              calledInstanceIndex),\n                      constArg(\n                          om.getTargetMethodOrFieldParameter(),\n                          getMethodOrFieldName(\n                              om.isTargetMethodOrFieldFqn(),\n                              opcode,\n                              owner,\n                              name,\n                              desc)),\n                      constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                      constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                      selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n                  invokeBTraceAction(asm, om);\n                  asm.closeLinkerCheck(l1);\n                }\n                if (l != null) {\n                  mv.visitLabel(l);\n                  insertFrameSameStack(l);\n                }\n              }\n            }\n          }\n\n          @Override\n          protected void onAfterPutField(int opcode, String owner, String name, String desc) {\n            if (where == Where.AFTER\n                && matches(targetClassName, owner.replace('/', '.'))\n                && matches(targetFieldName, name)) {\n              Type fieldType = Type.getType(desc);\n\n              addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n              addExtraTypeInfo(om.getTargetInstanceParameter(), Type.getObjectType(owner));\n              ValidationResult vr = validateArguments(om, actionArgTypes, new Type[] {fieldType});\n\n              if (vr.isValid()) {\n                Label l = levelCheckAfter(om, bcn.getClassName(true));\n\n                Label l1 = asm.openLinkerCheck();\n                loadArguments(\n                    localVarArg(vr.getArgIdx(0), fieldType, fldValueIndex),\n                    isStaticAccess\n                        ? constArg(om.getTargetInstanceParameter(), null)\n                        : localVarArg(\n                            om.getTargetInstanceParameter(),\n                            Constants.OBJECT_TYPE,\n                            calledInstanceIndex),\n                    constArg(\n                        om.getTargetMethodOrFieldParameter(),\n                        getMethodOrFieldName(\n                            om.isTargetMethodOrFieldFqn(),\n                            opcode,\n                            owner,\n                            name,\n                            desc)),\n                    constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                    constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                    selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n                invokeBTraceAction(asm, om);\n                asm.closeLinkerCheck(l1);\n                if (l != null) {\n                  mv.visitLabel(l);\n                  insertFrameSameStack(l);\n                }\n              }\n            }\n          }\n        }; // </editor-fold>\n\n      case INSTANCEOF:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"InstanceOf Instrumentor\">\n        return new TypeCheckInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n          ValidationResult vr;\n          Type castType = Constants.OBJECT_TYPE;\n          int castTypeIndex = -1;\n\n          {\n            addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n            addExtraTypeInfo(om.getTargetInstanceParameter(), Constants.OBJECT_TYPE);\n          }\n\n          private void callAction(String cName) {\n            if (vr.isValid()) {\n              Label l = levelCheck(om, bcn.getClassName(true));\n\n              Label l1 = asm.openLinkerCheck();\n              loadArguments(\n                  constArg(vr.getArgIdx(0), cName),\n                  constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                  constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                  selfArg(om.getSelfParameter(), Type.getObjectType(className)),\n                  localVarArg(\n                      om.getTargetInstanceParameter(), Constants.OBJECT_TYPE, castTypeIndex));\n\n              invokeBTraceAction(asm, om);\n              asm.closeLinkerCheck(l1);\n              if (l != null) {\n                mv.visitLabel(l);\n                insertFrameSameStack(l);\n              }\n            }\n          }\n\n          @Override\n          protected void onBeforeTypeCheck(int opcode, String desc) {\n            if (opcode == INSTANCEOF) {\n              castType = Type.getObjectType(desc);\n              vr = validateArguments(om, actionArgTypes, new Type[] {Constants.STRING_TYPE});\n              if (vr.isValid()) {\n                if (!vr.isAny()) {\n                  asm.dup();\n                  castTypeIndex = storeAsNew();\n                }\n                if (where == Where.BEFORE) {\n                  callAction(castType.getClassName());\n                }\n              }\n            }\n          }\n\n          @Override\n          protected void onAfterTypeCheck(int opcode, String desc) {\n            if (opcode == INSTANCEOF) {\n              castType = Type.getObjectType(desc);\n              vr = validateArguments(om, actionArgTypes, new Type[] {Constants.STRING_TYPE});\n              if (vr.isValid()) {\n                if (where == Where.AFTER) {\n                  callAction(castType.getClassName());\n                }\n              }\n            }\n          }\n        }; // </editor-fold>\n\n      case LINE:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"Line Instrumentor\">\n        return new LineNumberInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n\n          private final int onLine = loc.getLine();\n\n          private void callOnLine(int line) {\n            addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n            ValidationResult vr = validateArguments(om, actionArgTypes, new Type[] {Type.INT_TYPE});\n            if (vr.isValid()) {\n              Label l = levelCheck(om, bcn.getClassName(true));\n              Label l1 = asm.openLinkerCheck();\n              loadArguments(\n                  constArg(vr.getArgIdx(0), line),\n                  constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                  constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                  selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n              invokeBTraceAction(asm, om);\n              asm.closeLinkerCheck(l1);\n              if (l != null) {\n                mv.visitLabel(l);\n                insertFrameSameStack(l);\n              }\n            }\n          }\n\n          @Override\n          protected void onBeforeLine(int line) {\n            if ((line == onLine || onLine == -1) && where == Where.BEFORE) {\n              callOnLine(line);\n            }\n          }\n\n          @Override\n          protected void onAfterLine(int line) {\n            if ((line == onLine || onLine == -1) && where == Where.AFTER) {\n              callOnLine(line);\n            }\n          }\n        }; // </editor-fold>\n\n      case NEW:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"New Instance Instrumentor\">\n        return new ObjectAllocInstrumentor(\n            cl,\n            mv,\n            mHelper,\n            className,\n            superName,\n            access,\n            name,\n            desc,\n            om.getReturnParameter() != -1) {\n\n          @Override\n          protected void beforeObjectNew(String desc) {\n            if (loc.getWhere() == Where.BEFORE) {\n              String extName = desc.replace('/', '.');\n              if (matches(loc.getClazz(), extName)) {\n                addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n                ValidationResult vr =\n                    validateArguments(om, actionArgTypes, new Type[] {Constants.STRING_TYPE});\n                if (vr.isValid()) {\n                  Label l = levelCheck(om, bcn.getClassName(true));\n                  Label l1 = asm.openLinkerCheck();\n                  loadArguments(\n                      constArg(vr.getArgIdx(0), extName),\n                      constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                      constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                      selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n                  invokeBTraceAction(asm, om);\n                  asm.closeLinkerCheck(l1);\n                  if (l != null) {\n                    mv.visitLabel(l);\n                    insertFrameSameStack(l);\n                  }\n                }\n              }\n            }\n          }\n\n          @Override\n          protected void afterObjectNew(String desc) {\n            if (loc.getWhere() == Where.AFTER) {\n              String extName = desc.replace('/', '.');\n              if (matches(loc.getClazz(), extName)) {\n                Type instType = Type.getObjectType(desc);\n\n                addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n                addExtraTypeInfo(om.getReturnParameter(), instType);\n                ValidationResult vr =\n                    validateArguments(om, actionArgTypes, new Type[] {Constants.STRING_TYPE});\n                if (vr.isValid()) {\n                  int returnValIndex = -1;\n                  Label l = levelCheck(om, bcn.getClassName(true));\n                  if (om.getReturnParameter() != -1) {\n                    asm.dupValue(instType);\n                    returnValIndex = storeAsNew();\n                  }\n                  Label l1 = asm.openLinkerCheck();\n                  loadArguments(\n                      constArg(vr.getArgIdx(0), extName),\n                      localVarArg(om.getReturnParameter(), instType, returnValIndex),\n                      constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                      constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                      selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n                  invokeBTraceAction(asm, om);\n                  asm.closeLinkerCheck(l1);\n                  if (l != null) {\n                    mv.visitLabel(l);\n                    insertFrameSameStack(l);\n                  }\n                }\n              }\n            }\n          }\n        }; // </editor-fold>\n\n      case NEWARRAY:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"New Array Instrumentor\">\n        return new ArrayAllocInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n\n          @Override\n          protected void onBeforeArrayNew(String desc, int dims) {\n            if (where == Where.BEFORE) {\n              String extName = TypeUtils.getJavaType(desc);\n              String type = loc.getClazz();\n              if (matches(type, extName)) {\n                addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n                ValidationResult vr =\n                    validateArguments(\n                        om, actionArgTypes, new Type[] {Constants.STRING_TYPE, Type.INT_TYPE});\n                if (vr.isValid()) {\n                  Label l = levelCheck(om, bcn.getClassName(true));\n                  Label l1 = asm.openLinkerCheck();\n                  loadArguments(\n                      constArg(vr.getArgIdx(0), extName),\n                      constArg(vr.getArgIdx(1), dims),\n                      constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                      constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                      selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n                  invokeBTraceAction(asm, om);\n                  asm.closeLinkerCheck(l1);\n                  if (l != null) {\n                    mv.visitLabel(l);\n                    insertFrameSameStack(l);\n                  }\n                }\n              }\n            }\n          }\n\n          @Override\n          protected void onAfterArrayNew(String desc, int dims) {\n            if (where == Where.AFTER) {\n              String extName = TypeUtils.getJavaType(desc);\n              String type = loc.getClazz();\n              if (matches(type, extName)) {\n                StringBuilder arrayType = new StringBuilder();\n                for (int i = 0; i < dims; i++) {\n                  arrayType.append(\"[\");\n                }\n                arrayType.append(desc);\n                Type instType = Type.getObjectType(arrayType.toString());\n                addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n                addExtraTypeInfo(om.getReturnParameter(), instType);\n                ValidationResult vr =\n                    validateArguments(\n                        om, actionArgTypes, new Type[] {Constants.STRING_TYPE, Type.INT_TYPE});\n                if (vr.isValid()) {\n                  int returnValIndex = -1;\n                  Label l = levelCheck(om, bcn.getClassName(true));\n                  if (om.getReturnParameter() != -1) {\n                    asm.dupValue(instType);\n                    returnValIndex = storeAsNew();\n                  }\n                  Label l1 = asm.openLinkerCheck();\n                  loadArguments(\n                      constArg(vr.getArgIdx(0), extName),\n                      constArg(vr.getArgIdx(1), dims),\n                      localVarArg(om.getReturnParameter(), instType, returnValIndex),\n                      constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                      constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                      selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n                  invokeBTraceAction(asm, om);\n                  asm.closeLinkerCheck(l1);\n                  if (l != null) {\n                    mv.visitLabel(l);\n                    insertFrameSameStack(l);\n                  }\n                }\n              }\n            }\n          }\n        }; // </editor-fold>\n\n      case RETURN:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"Return Instrumentor\">\n        if (where != Where.BEFORE) {\n          return mv;\n        }\n        return new MethodReturnInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n          int retValIndex;\n          private int retTmpIndex = Integer.MIN_VALUE;\n\n          final ValidationResult vr;\n          private boolean generatingCode = false;\n          private MethodTrackingContext trackingCtx;\n\n          {\n            addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n            addExtraTypeInfo(om.getReturnParameter(), getReturnType());\n\n            vr = validateArguments(om, actionArgTypes, Type.getArgumentTypes(getDescriptor()));\n            int mid = MethodID.getMethodId(className, name, desc);\n            trackingCtx =\n                mHelper.getOrCreateTrackingContext(\n                    mid,\n                    () -> new MethodTrackingContext(mv, asm, mHelper, bcn.getClassName(true), mid));\n          }\n\n          private void callAction(int retOpCode) {\n            if (!vr.isValid()) {\n              return;\n            }\n\n            Label l1 = asm.openLinkerCheck();\n\n            boolean boxReturnValue = false;\n            Type probeRetType = getReturnType();\n            if (om.getReturnParameter() != -1) {\n              Type retType =\n                  Type.getArgumentTypes(om.getTargetDescriptor())[om.getReturnParameter()];\n              if (probeRetType.equals(Type.VOID_TYPE)) {\n                if (TypeUtils.isAnyType(retType)) {\n                  // no return value but still tracking\n                  // let's push a synthetic AnyType value on stack\n                  asm.getStatic(\n                      Type.getInternalName(AnyType.class), \"VOID\", Constants.ANYTYPE_DESC);\n                  probeRetType = Constants.OBJECT_TYPE;\n                } else if (Constants.VOIDREF_TYPE.equals(retType)) {\n                  // intercepting return from method not returning value (void)\n                  // the receiver accepts java.lang.Void only so let's push NULL on stack\n                  asm.loadNull();\n                  probeRetType = Constants.VOIDREF_TYPE;\n                }\n              } else {\n                if (Type.getReturnType(om.getTargetDescriptor()).getSort() == Type.VOID) {\n                  asm.dupReturnValue(retOpCode);\n                }\n                boxReturnValue = TypeUtils.isAnyType(retType);\n              }\n              retValIndex = storeAsNew();\n            }\n\n            loadArguments(\n                vr,\n                actionArgTypes,\n                isStatic(),\n                constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                constArg(om.getClassNameParameter(), className.replace(\"/\", \".\")),\n                localVarArg(om.getReturnParameter(), probeRetType, retValIndex, boxReturnValue),\n                selfArg(om.getSelfParameter(), Type.getObjectType(className)),\n                new ArgumentProvider(asm, om.getDurationParameter()) {\n                  @Override\n                  public void doProvide() {\n                    if (trackingCtx != null) {\n                      trackingCtx.emitDuration();\n                    }\n                  }\n                });\n\n            invokeBTraceAction(asm, om);\n            asm.closeLinkerCheck(l1);\n          }\n\n          @Override\n          protected void onMethodReturn(int opcode) {\n            // If we're adding duration but the probe does not request @Return,\n            // store the return value to a temp local so the epilogue doesn't\n            // carry a live value on the stack across branches; reload before return.\n            boolean needsTempStore =\n                om.getDurationParameter() != -1\n                    && om.getReturnParameter() == -1\n                    && !Type.VOID_TYPE.equals(getReturnType());\n            // Do not store the return value into a temp local here.\n            // Keep it on the operand stack across the epilogue so the join\n            // does not introduce a locals delta. The simulated stack tracks\n            // the correct max depth (int under long ops).\n\n            if (vr.isValid() || vr.isAny()) {\n              int mid = MethodID.getMethodId(className, name, desc);\n              trackingCtx.emitTestSample(true, mid);\n\n              if (numActionArgs == 0) {\n                invokeBTraceAction(asm, om);\n              } else {\n                callAction(opcode);\n              }\n              trackingCtx.emitElse();\n            }\n          }\n\n          @Override\n          protected void onMethodEntry() {\n            if (vr.isValid() || vr.isAny()) {\n              try {\n                if (!generatingCode) {\n                  generatingCode = true;\n                  int mid = MethodID.getMethodId(className, name, desc);\n\n                  if (om.getDurationParameter() != -1) {\n                    trackingCtx.emitEntry(true, om.getSamplerKind(), om.getSamplerMean(), mid, getLevelStrSafe(om));\n                  } else {\n                    trackingCtx.emitEntry(false, om.getSamplerKind(), om.getSamplerMean(), mid, getLevelStrSafe(om));\n                  }\n                }\n              } finally {\n                generatingCode = false;\n              }\n            }\n          }\n        };\n        // </editor-fold>\n\n      case SYNC_ENTRY:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"SyncEntry Instrumentor\">\n        return new SynchronizedInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n          int storedObjIdx = -1;\n          final ValidationResult vr;\n          private MethodTrackingContext trackingCtx;\n\n          {\n            addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n            addExtraTypeInfo(om.getTargetInstanceParameter(), Constants.OBJECT_TYPE);\n            vr = validateArguments(om, actionArgTypes, Type.getArgumentTypes(getDescriptor()));\n            int mid = MethodID.getMethodId(className, name, desc);\n            trackingCtx =\n                mHelper.getOrCreateTrackingContext(\n                    mid,\n                    () -> new MethodTrackingContext(mv, asm, mHelper, bcn.getClassName(true), mid));\n          }\n\n          @Override\n          protected void onBeforeSyncEntry() {\n            if (vr.isValid()) {\n              Label l = levelCheckBefore(om, bcn.getClassName(true));\n\n              if (om.getTargetInstanceParameter() != -1) {\n\n                if (isSyncMethod) {\n                  if (!isStatic) {\n                    storedObjIdx = 0;\n                  } else {\n                    asm.ldc(Type.getObjectType(className));\n                    storedObjIdx = storeAsNew();\n                  }\n                } else {\n                  asm.dup();\n                  storedObjIdx = storeAsNew();\n                }\n              }\n\n              if (where == Where.BEFORE) {\n                Label l1 = asm.openLinkerCheck();\n                loadArguments(\n                    vr,\n                    actionArgTypes,\n                    isStatic(),\n                    constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                    constArg(om.getClassNameParameter(), className.replace(\"/\", \".\")),\n                    localVarArg(\n                        om.getTargetInstanceParameter(), Constants.OBJECT_TYPE, storedObjIdx),\n                    selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n                invokeBTraceAction(asm, om);\n                asm.closeLinkerCheck(l1);\n              }\n              if (l != null) {\n                mv.visitLabel(l);\n                insertFrameSameStack(l);\n              }\n            }\n          }\n\n          @Override\n          protected void onAfterSyncEntry() {\n            if (where == Where.AFTER) {\n              if (vr.isValid()) {\n                Label l = levelCheckAfter(om, bcn.getClassName(true));\n\n                Label l1 = asm.openLinkerCheck();\n                loadArguments(\n                    vr,\n                    actionArgTypes,\n                    isStatic(),\n                    constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                    constArg(om.getClassNameParameter(), className.replace(\"/\", \".\")),\n                    localVarArg(\n                        om.getTargetInstanceParameter(), Constants.OBJECT_TYPE, storedObjIdx),\n                    selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n                invokeBTraceAction(asm, om);\n                asm.closeLinkerCheck(l1);\n                if (l != null) {\n                  mv.visitLabel(l);\n                  insertFrameSameStack(l);\n                }\n              }\n            }\n          }\n\n          @Override\n          protected void onBeforeSyncExit() {}\n\n          @Override\n          protected void onAfterSyncExit() {}\n        }; // </editor-fold>\n\n      case SYNC_EXIT:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"SyncExit Instrumentor\">\n        return new SynchronizedInstrumentor(\n            cl, mv, mHelper, className, superName, access, name, desc) {\n          int storedObjIdx = -1;\n          final ValidationResult vr;\n          private MethodTrackingContext trackingCtx;\n\n          {\n            addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n            addExtraTypeInfo(om.getTargetInstanceParameter(), Constants.OBJECT_TYPE);\n            vr = validateArguments(om, actionArgTypes, Type.getArgumentTypes(getDescriptor()));\n            int mid = MethodID.getMethodId(className, name, desc);\n            trackingCtx =\n                mHelper.getOrCreateTrackingContext(\n                    mid,\n                    () -> new MethodTrackingContext(mv, asm, mHelper, bcn.getClassName(true), mid));\n          }\n\n          private void loadActionArgs() {\n            loadArguments(\n                vr,\n                actionArgTypes,\n                isStatic(),\n                constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                constArg(om.getClassNameParameter(), className.replace(\"/\", \".\")),\n                localVarArg(om.getTargetInstanceParameter(), Constants.OBJECT_TYPE, storedObjIdx),\n                selfArg(om.getSelfParameter(), Type.getObjectType(className)),\n                new MethodInstrumentor.ArgumentProvider(asm, om.getDurationParameter()) {\n                  @Override\n                  public void doProvide() {\n                    if (trackingCtx != null) {\n                      trackingCtx.emitDuration();\n                    }\n                  }\n                });\n          }\n\n          @Override\n          protected void onBeforeSyncExit() {\n            if (!vr.isValid()) {\n              return;\n            }\n            Label l = levelCheckBefore(om, bcn.getClassName(true));\n\n            if (om.getTargetInstanceParameter() != -1) {\n              if (isSyncMethod) {\n                if (!isStatic) {\n                  storedObjIdx = 0;\n                } else {\n                  asm.ldc(Type.getObjectType(className));\n                  storedObjIdx = storeAsNew();\n                }\n              } else {\n                asm.dup();\n                storedObjIdx = storeAsNew();\n              }\n            }\n            if (where == Where.BEFORE) {\n              Label l1 = asm.openLinkerCheck();\n              loadActionArgs();\n              invokeBTraceAction(asm, om);\n              asm.closeLinkerCheck(l1);\n            }\n            if (l != null) {\n              mv.visitLabel(l);\n              insertFrameSameStack(l);\n            }\n          }\n\n          @Override\n          protected void onAfterSyncExit() {\n            if (!vr.isValid()) {\n              return;\n            }\n            if (where == Where.AFTER) {\n              loadActionArgs();\n              invokeBTraceAction(asm, om);\n            }\n          }\n\n          @Override\n          protected void onAfterSyncEntry() {\n            if (!vr.isValid()) {\n              return;\n            }\n            if (om.getDurationParameter() != -1) {\n              int mid = MethodID.getMethodId(className, name, desc);\n              trackingCtx.emitEntry(true, Sampled.Sampler.None, 0, mid, \"\");\n            }\n          }\n\n          @Override\n          protected void onBeforeSyncEntry() {}\n        }; // </editor-fold>\n\n      case THROW:\n        // <editor-fold defaultstate=\"collapsed\" desc=\"Throw Instrumentor\">\n        return new ThrowInstrumentor(cl, mv, mHelper, className, superName, access, name, desc) {\n\n          @Override\n          protected void onThrow() {\n            addExtraTypeInfo(om.getSelfParameter(), Type.getObjectType(className));\n            addExtraTypeInfo(om.getTargetInstanceParameter(), Constants.THROWABLE_TYPE);\n            ValidationResult vr =\n                validateArguments(om, actionArgTypes, Type.getArgumentTypes(getDescriptor()));\n            if (vr.isValid()) {\n              int throwableIndex = -1;\n              Label l = levelCheck(om, bcn.getClassName(true));\n              if (om.getTargetInstanceParameter() != -1) {\n                asm.dup();\n                throwableIndex = storeAsNew();\n              }\n              Label l1 = asm.openLinkerCheck();\n              loadArguments(\n                  localVarArg(\n                      om.getTargetInstanceParameter(), Constants.THROWABLE_TYPE, throwableIndex),\n                  constArg(om.getClassNameParameter(), className.replace('/', '.')),\n                  constArg(om.getMethodParameter(), getName(om.isMethodFqn())),\n                  selfArg(om.getSelfParameter(), Type.getObjectType(className)));\n\n              invokeBTraceAction(asm, om);\n              asm.closeLinkerCheck(l1);\n              if (l != null) {\n                mv.visitLabel(l);\n                insertFrameSameStack(l);\n              }\n            }\n          }\n        }; // </editor-fold>\n    }\n    return mv;\n  }\n\n  @Override\n  public void visitEnd() {\n    cv.visitEnd();\n  }\n\n  static String getActionMethodName(BTraceProbe bp, String name) {\n    return InstrumentUtils.getActionPrefix(bp.getClassName(true)) + name;\n  }\n\n  private String getActionMethodName(String name) {\n    return getActionMethodName(bcn, name);\n  }\n\n  private void invokeBTraceAction(Assembler asm, OnMethod om) {\n    MethodType mt =\n        MethodType.methodType(\n            CallSite.class,\n            MethodHandles.Lookup.class,\n            String.class,\n            MethodType.class,\n            String.class);\n\n    asm.invokeDynamic(\n        getActionMethodName(om.getTargetName()),\n        om.getTargetDescriptor().replace(Constants.ANYTYPE_DESC, Constants.OBJECT_DESC),\n        new Handle(\n            H_INVOKESTATIC,\n            \"org/openjdk/btrace/runtime/IndyDispatcher\",\n            \"bootstrap\",\n            mt.toMethodDescriptorString(),\n            false),\n        bcn.getClassName(true));\n    calledOnMethods.add(om);\n    om.setCalled();\n  }\n\n  /**\n   * Currently used for regex matching in the 'location' attribute\n   *\n   * @param pattern\n   * @param input\n   * @return\n   */\n  private boolean matches(String pattern, String input) {\n    if (pattern.length() == 0) {\n      return false;\n    }\n    if (pattern.charAt(0) == '/' && Constants.REGEX_SPECIFIER.matcher(pattern).matches()) {\n      try {\n        return input.matches(pattern.substring(1, pattern.length() - 1));\n      } catch (PatternSyntaxException pse) {\n        reportPatternSyntaxException(pattern.substring(1, pattern.length() - 1));\n        return false;\n      }\n    } else {\n      return pattern.equals(input);\n    }\n  }\n\n  private boolean typeMatches(String decl, String desc, boolean exactTypeMatch) {\n    // empty type declaration matches any method signature\n    if (decl.isEmpty()) {\n      return true;\n    } else {\n      String d = TypeUtils.declarationToDescriptor(decl);\n      Type[] argTypesLeft = Type.getArgumentTypes(d);\n      Type[] argTypesRight = Type.getArgumentTypes(desc);\n      Type retTypeLeft = Type.getReturnType(d);\n      Type retTypeRight = Type.getReturnType(desc);\n      return InstrumentUtils.isAssignable(retTypeLeft, retTypeRight, cl, exactTypeMatch)\n          && InstrumentUtils.isAssignable(argTypesLeft, argTypesRight, cl, exactTypeMatch);\n    }\n  }\n\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/Level.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport org.openjdk.btrace.runtime.Interval;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic class Level {\n  private final Interval value;\n\n  public Level() {\n    this(\">0\");\n  }\n\n  private Level(Interval i) {\n    value = i;\n  }\n\n  private Level(String s) {\n    this(Interval.fromString(s));\n  }\n\n  public static Level fromString(String s) {\n    return new Level(s);\n  }\n\n  public Interval getValue() {\n    return value;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/LineNumberInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * This visitor helps in inserting code whenever a source line is reached. The code to insert on\n * line number may be decided by derived class. By default, this class inserts code to print the\n * line.\n *\n * @author A. Sundararajan\n */\npublic class LineNumberInstrumentor extends MethodInstrumentor {\n  private int lastLine;\n\n  public LineNumberInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  public void visitLineNumber(int line, Label start) {\n    if (lastLine != 0) {\n      onAfterLine(line - 1);\n    }\n    if (!isConstructor() || isPrologueVisited()) {\n      onBeforeLine(line);\n    }\n    lastLine = line;\n    super.visitLineNumber(line, start);\n  }\n\n  @Override\n  public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean iface) {\n    boolean beforeConstructor = !isPrologueVisited();\n    super.visitMethodInsn(opcode, owner, name, desc, iface);\n    if (lastLine != -1 && beforeConstructor) {\n      onBeforeLine(lastLine);\n    }\n  }\n\n  protected void onBeforeLine(int line) {\n    asm.println(\"before line \" + line);\n  }\n\n  protected void onAfterLine(int line) {\n    asm.println(\"after line \" + line);\n  }\n\n  @Override\n  public void visitEnd() {\n    if (lastLine != -1) {\n      onAfterLine(lastLine);\n    }\n    super.visitEnd();\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/LinkerInstrumentor.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.ClassWriter;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\n\n/**\n * This is used to inject code to set/unset linking flag to make sure no BTrace\n * code is executed while invokedynamic is being linked.\n */\npublic final class LinkerInstrumentor {\n    private static class LinkerMethodVisitor extends MethodVisitor {\n        private final Label tryStart = new Label();\n        private final Label tryEnd = new Label();\n        private final Label finallyStart = new Label();\n\n        private int maxVarIndex;\n\n        public LinkerMethodVisitor(MethodVisitor mv, int argStackSize) {\n            super(Opcodes.ASM9, mv);\n            this.maxVarIndex = argStackSize;\n        }\n\n        @Override\n        public void visitCode() {\n            mv.visitTryCatchBlock(tryStart, tryEnd, finallyStart, null);\n            mv.visitLabel(tryStart);\n            mv.visitMethodInsn(Opcodes.INVOKESTATIC, \"org/openjdk/btrace/runtime/LinkingFlag\", \"guardLinking\", \"()I\", false);\n            mv.visitInsn(Opcodes.POP); // discard the result\n            super.visitCode();\n        }\n\n        @Override\n        public void visitVarInsn(int opcode, int varIndex) {\n            super.visitVarInsn(opcode, varIndex);\n            maxVarIndex = Math.max(maxVarIndex, varIndex);\n        }\n\n        @Override\n        public void visitInsn(int opcode) {\n            if (opcode == Opcodes.ARETURN) {\n                mv.visitMethodInsn(Opcodes.INVOKESTATIC, \"org/openjdk/btrace/runtime/LinkingFlag\", \"reset\", \"()V\", false);\n            }\n            super.visitInsn(opcode);\n        }\n\n        @Override\n        public void visitMaxs(int maxStack, int maxLocals) {\n            mv.visitLabel(tryEnd);\n            mv.visitLabel(finallyStart);\n            mv.visitVarInsn(Opcodes.ASTORE, maxVarIndex);\n            mv.visitMethodInsn(Opcodes.INVOKESTATIC, \"org/openjdk/btrace/runtime/LinkingFlag\", \"reset\", \"()V\", false);\n            mv.visitVarInsn(Opcodes.ALOAD, maxVarIndex);\n            mv.visitInsn(Opcodes.ATHROW);\n            super.visitMaxs(0, maxVarIndex);\n        }\n    }\n\n    private static class LinkerClassVisitor extends ClassVisitor {\n        public LinkerClassVisitor(ClassVisitor cv) {\n            super(Opcodes.ASM9, cv);\n        }\n\n        @Override\n        public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {\n            MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);\n            if (name.equals(\"linkCallSite\") || name.equals(\"linkMethodHandleConstant\")) {\n                int argStackSize = Type.getArgumentsAndReturnSizes(descriptor) - 1;\n                mv = new LinkerMethodVisitor(mv, argStackSize);\n            }\n            return mv;\n        }\n    }\n    public static byte[] addGuard(byte[] classData) {\n        ClassReader cr = new ClassReader(classData);\n        ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);\n        cr.accept(new LinkerClassVisitor(cw), ClassReader.EXPAND_FRAMES);\n        return cw.toByteArray();\n    }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/Location.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/**\n * This class is used to store data of the annotation Location. We can not read the Location\n * annotation using reflection API [because we strip {@code @OnMethod} annotated methods before\n * defineClass]. Instead, we read Location annotation while parsing the BTrace class and store the\n * data in an instance of this class. Please note that the get/set methods have to be in sync with\n * Location annotation.\n *\n * @author A. Sundararajan\n */\npublic class Location {\n  private String clazz = \"\";\n  private String method = \"\";\n  private String type = \"\";\n  private String field = \"\";\n  private int line = 0;\n  private Kind value = Kind.ENTRY;\n  private Where where = Where.BEFORE;\n\n  public String getClazz() {\n    return clazz;\n  }\n\n  public void setClazz(String clazz) {\n    this.clazz = clazz;\n  }\n\n  public String getMethod() {\n    return method;\n  }\n\n  public void setMethod(String method) {\n    this.method = method;\n  }\n\n  public String getField() {\n    return field;\n  }\n\n  public void setField(String field) {\n    this.field = field;\n  }\n\n  public int getLine() {\n    return line;\n  }\n\n  public void setLine(int line) {\n    this.line = line;\n  }\n\n  public String getType() {\n    return type;\n  }\n\n  public void setType(String type) {\n    this.type = type;\n  }\n\n  public Kind getValue() {\n    return value;\n  }\n\n  public void setValue(Kind value) {\n    this.value = value;\n  }\n\n  public Where getWhere() {\n    return where;\n  }\n\n  public void setWhere(Where where) {\n    this.where = where;\n  }\n\n  @Override\n  public String toString() {\n    return \"Location{\"\n        + \"clazz=\"\n        + clazz\n        + \", method=\"\n        + method\n        + \", type=\"\n        + type\n        + \", field=\"\n        + field\n        + \", line=\"\n        + line\n        + \", value=\"\n        + value\n        + \", where=\"\n        + where\n        + '}';\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodCallInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008-2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * This visitor helps in inserting code whenever a method call is done. The code to insert on method\n * calls may be decided by derived class. By default, this class inserts code to print the called\n * method.\n *\n * @author A. Sundararajan\n */\npublic class MethodCallInstrumentor extends MethodInstrumentor {\n  private int callId = 0;\n\n  public MethodCallInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean iface) {\n    if (name.startsWith(\"$btrace\")) {\n      super.visitMethodInsn(opcode, owner, name, desc, iface);\n      return;\n    }\n\n    callId++;\n\n    onBeforeCallMethod(opcode, owner, name, desc);\n    super.visitMethodInsn(opcode, owner, name, desc, iface);\n    onAfterCallMethod(opcode, owner, name, desc);\n  }\n\n  protected void onBeforeCallMethod(int opcode, String owner, String name, String desc) {\n    asm.println(\"before call: \" + owner + \".\" + name + desc);\n  }\n\n  protected void onAfterCallMethod(int opcode, String owner, String name, String desc) {\n    asm.println(\"after call: \" + owner + \".\" + name + desc);\n  }\n\n  protected int getCallId() {\n    return callId;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodEntryExitInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * Instruments method entry and exit points. For exit, both normal and abnormal (exception) return\n * points are instrumented. Subclasses can decide what code is inserted at entry/exit points.\n *\n * @author A. Sundararajan\n */\npublic class MethodEntryExitInstrumentor extends ErrorReturnInstrumentor {\n  public MethodEntryExitInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  protected void onMethodReturn(int opcode) {\n    asm.println(\"on method return\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodEntryInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * This visitor helps in inserting code whenever a method is entered. The code to insert on method\n * entry may be decided by derived class. By default, this class inserts code to print name and\n * signature of the method entered.\n *\n * @author A. Sundararajan\n */\npublic class MethodEntryInstrumentor extends MethodInstrumentor {\n  public MethodEntryInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  protected void visitMethodPrologue() {\n    onMethodEntry();\n  }\n\n  protected void onMethodEntry() {\n    asm.println(\"entering \" + getName() + getDescriptor());\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Type;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.runtime.Interval;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Base class for all out method instrumenting classes.\n *\n * @author A. Sundararajan\n */\npublic class MethodInstrumentor extends BTraceMethodVisitor {\n  private static final Logger log = LoggerFactory.getLogger(MethodInstrumentor.class);\n  protected final Assembler asm;\n  protected MethodTrackingContext trackingCtx;\n  MethodInstrumentor parent = null;\n  private final int access;\n  private final String parentClz;\n  private final String superClz;\n  private final String name;\n  private final String desc;\n  private final ClassLoader cl;\n  private int levelCheckVar = Integer.MIN_VALUE;\n  private final Type returnType;\n  private final Type[] argumentTypes;\n  private final Map<Integer, Type> extraTypes;\n  private Label skipLabel;\n  private boolean prologueVisited = false;\n\n  public MethodInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(mv, mHelper);\n    this.parentClz = parentClz;\n    this.superClz = superClz;\n    this.access = access;\n    this.name = name;\n    this.desc = desc;\n    returnType = Type.getReturnType(desc);\n    argumentTypes = Type.getArgumentTypes(desc);\n    extraTypes = new HashMap<>();\n    asm = new Assembler(this, mHelper);\n    this.cl = cl;\n  }\n\n  private static boolean isLevelCheck(Level level) {\n    return level != null && !level.getValue().equals(Interval.ge(0));\n  }\n\n  protected void visitMethodPrologue() {}\n\n  @Override\n  public final void visitCode() {\n    if (!isConstructor()) {\n      prologueVisited = true;\n      visitMethodPrologue();\n    }\n    super.visitCode();\n  }\n\n  @Override\n  public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean iface) {\n    super.visitMethodInsn(opcode, owner, name, desc, iface);\n    if (isConstructor() && !prologueVisited) {\n      if (name.equals(Constants.CONSTRUCTOR)\n          && (owner.equals(getParentClz())\n              || (getSuperClz() != null && owner.equals(getSuperClz())))) {\n        // super or this class constructor call.\n        // do method entry after that!\n        prologueVisited = true;\n        visitMethodPrologue();\n      }\n    }\n  }\n\n  @Override\n  public void visitInsn(int opcode) {\n    switch (opcode) {\n      case IRETURN:\n      case ARETURN:\n      case FRETURN:\n      case LRETURN:\n      case DRETURN:\n      case RETURN:\n        if (!prologueVisited) {\n          prologueVisited = true;\n          visitMethodPrologue();\n        }\n        break;\n      default:\n        break;\n    }\n    super.visitInsn(opcode);\n  }\n\n  public int getAccess() {\n    return access;\n  }\n\n  public final String getName() {\n    return getName(false);\n  }\n\n  public final String getName(boolean fqn) {\n    StringBuilder sb = new StringBuilder();\n    if (fqn) {\n      sb.append(Modifier.toString(access))\n          .append(' ')\n          .append(TypeUtils.descriptorToSimplified(desc, parentClz, name));\n    } else {\n      sb.append(name);\n    }\n    return sb.toString();\n  }\n\n  public final Label getSkipLabel() {\n    return skipLabel;\n  }\n\n  public final void setSkipLabel(Label skipLabel) {\n    this.skipLabel = skipLabel;\n  }\n\n  public final String getDescriptor() {\n    return desc;\n  }\n\n  public final Type getReturnType() {\n    return returnType;\n  }\n\n  protected void addExtraTypeInfo(int index, Type type) {\n    if (index != -1) {\n      extraTypes.put(index, type);\n    }\n  }\n\n  protected void loadArguments(ArgumentProvider... argumentProviders) {\n    Arrays.sort(argumentProviders, ArgumentProvider.COMPARATOR);\n\n    for (ArgumentProvider provider : argumentProviders) {\n      if (provider != null) provider.provide();\n    }\n  }\n\n  protected void loadArguments(\n      ValidationResult vr,\n      Type[] actionArgTypes,\n      boolean isStatic,\n      ArgumentProvider... argumentProviders) {\n    int ptr = isStatic ? 0 : 1;\n    List<ArgumentProvider> argProvidersList =\n        new ArrayList<>(argumentProviders.length + vr.getArgCnt());\n    argProvidersList.addAll(Arrays.asList(argumentProviders));\n    for (int i = 0; i < vr.getArgCnt(); i++) {\n      int index = vr.getArgIdx(i);\n      Type t = actionArgTypes[index];\n      if (TypeUtils.isAnyTypeArray(t)) {\n        argProvidersList.add(anytypeArg(index, ptr));\n        ptr++;\n      } else {\n        argProvidersList.add(localVarArg(index, t, ptr));\n        ptr += actionArgTypes[index].getSize();\n      }\n    }\n    loadArguments(argProvidersList);\n  }\n\n  private void loadArguments(List<ArgumentProvider> argumentProviders) {\n    argumentProviders.sort(ArgumentProvider.COMPARATOR);\n    for (ArgumentProvider ap : argumentProviders) {\n      if (ap != null) {\n        ap.provide();\n      }\n    }\n  }\n\n  public void loadThis() {\n    if ((access & ACC_STATIC) != 0) {\n      throw new IllegalStateException(\"no 'this' inside static method\");\n    }\n    visitVarInsn(ALOAD, 0);\n  }\n\n  public int[] backupStack(Type[] methodArgTypes, boolean isStatic) {\n    int[] backupArgsIndexes = new int[methodArgTypes.length + 1];\n    int upper = methodArgTypes.length - 1;\n\n    for (int i = 0; i < methodArgTypes.length; i++) {\n      Type t = methodArgTypes[upper - i];\n      int index = storeAsNew();\n      backupArgsIndexes[upper - i + 1] = index;\n    }\n\n    if (!isStatic) {\n      int index = storeAsNew(); // store *callee*\n      backupArgsIndexes[0] = index;\n    }\n    return backupArgsIndexes;\n  }\n\n  public void restoreStack(int[] backupArgsIndexes, boolean isStatic) {\n    restoreStack(backupArgsIndexes, argumentTypes, isStatic);\n  }\n\n  public void restoreStack(int[] backupArgsIndexes, Type[] methodArgTypes, boolean isStatic) {\n    int upper = methodArgTypes.length - 1;\n    if (!isStatic) {\n      asm.loadLocal(Constants.OBJECT_TYPE, backupArgsIndexes[0]);\n    }\n\n    for (int i = methodArgTypes.length - 1; i > -1; i--) {\n      asm.loadLocal(methodArgTypes[upper - i], backupArgsIndexes[upper - i + 1]);\n    }\n  }\n\n  protected final ArgumentProvider localVarArg(int index, Type type, int ptr) {\n    return new LocalVarArgProvider(asm, index, type, ptr);\n  }\n\n  protected final ArgumentProvider localVarArg(int index, Type type, int ptr, boolean boxValue) {\n    return new LocalVarArgProvider(asm, index, type, ptr, boxValue);\n  }\n\n  protected final ArgumentProvider constArg(int index, Object val) {\n    return new ConstantArgProvider(asm, index, val);\n  }\n\n  protected final ArgumentProvider selfArg(int index, Type type) {\n    return isStatic() ? constArg(index, null) : localVarArg(index, type, 0);\n  }\n\n  protected final ArgumentProvider anytypeArg(int index, int basePtr) {\n    return new AnyTypeArgProvider(asm, index, basePtr);\n  }\n\n  protected final ArgumentProvider anytypeArg(int index, int basePtr, Type... argTypes) {\n    return new AnyTypeArgProvider(asm, index, basePtr, argTypes);\n  }\n\n  protected final boolean isStatic() {\n    return (getAccess() & ACC_STATIC) != 0;\n  }\n\n  protected final boolean isConstructor() {\n    return Constants.CONSTRUCTOR.equals(name);\n  }\n\n  public void returnValue() {\n    super.visitInsn(returnType.getOpcode(IRETURN));\n  }\n\n  protected String getParentClz() {\n    return parentClz;\n  }\n\n  protected String getSuperClz() {\n    return superClz;\n  }\n\n  protected ValidationResult validateArguments(\n      OnMethod om, Type[] actionArgTypes, Type[] methodArgTypes) {\n    int specialArgsCount = 0;\n\n    if (om.getSelfParameter() != -1) {\n      Type selfType = extraTypes.get(om.getSelfParameter());\n      if (selfType == null) {\n        if (!TypeUtils.isObject(actionArgTypes[om.getSelfParameter()])) {\n          report(\n              \"Invalid @Self parameter. @Self parameter is not java.lang.Object. Expected \"\n                  + Constants.OBJECT_TYPE\n                  + \", Received \"\n                  + actionArgTypes[om.getSelfParameter()]);\n          return ValidationResult.INVALID;\n        }\n      } else {\n        if (!InstrumentUtils.isAssignable(\n            actionArgTypes[om.getSelfParameter()], selfType, cl, om.isExactTypeMatch())) {\n          report(\n              \"Invalid @Self parameter. @Self parameter is not compatible. Expected \"\n                  + selfType\n                  + \", Received \"\n                  + actionArgTypes[om.getSelfParameter()]);\n          return ValidationResult.INVALID;\n        }\n      }\n      specialArgsCount++;\n    }\n    if (om.getReturnParameter() != -1) {\n      Type type = extraTypes.get(om.getReturnParameter());\n      if (type == null) {\n        type = returnType;\n      }\n      if (type == null) {\n        if (!TypeUtils.isObject(actionArgTypes[om.getReturnParameter()])) {\n          report(\n              \"Invalid @Return parameter. @Return parameter is not java.lang.Object. Expected \"\n                  + Constants.OBJECT_TYPE\n                  + \", Received \"\n                  + actionArgTypes[om.getReturnParameter()]);\n          return ValidationResult.INVALID;\n        }\n      } else {\n        if (!InstrumentUtils.isAssignable(\n            actionArgTypes[om.getReturnParameter()], type, cl, om.isExactTypeMatch())) {\n          report(\n              \"Invalid @Return parameter. Expected '\"\n                  + returnType\n                  + \", received \"\n                  + actionArgTypes[om.getReturnParameter()]);\n          return ValidationResult.INVALID;\n        }\n      }\n      specialArgsCount++;\n    }\n    if (om.getTargetMethodOrFieldParameter() != -1) {\n      if (!(InstrumentUtils.isAssignable(\n          actionArgTypes[om.getTargetMethodOrFieldParameter()],\n          Constants.STRING_TYPE,\n          cl,\n          om.isExactTypeMatch()))) {\n        report(\n            \"Invalid @TargetMethodOrField parameter. Expected \"\n                + Constants.STRING_TYPE\n                + \", received \"\n                + actionArgTypes[om.getTargetMethodOrFieldParameter()]);\n        return ValidationResult.INVALID;\n      }\n      specialArgsCount++;\n    }\n    if (om.getTargetInstanceParameter() != -1) {\n      Type calledType = extraTypes.get(om.getTargetInstanceParameter());\n      if (calledType == null) {\n        if (!TypeUtils.isObject(actionArgTypes[om.getTargetInstanceParameter()])) {\n          report(\n              \"Invalid @TargetInstance parameter. @TargetInstance parameter is not java.lang.Object. Expected \"\n                  + Constants.OBJECT_TYPE\n                  + \", Received \"\n                  + actionArgTypes[om.getTargetInstanceParameter()]);\n          return ValidationResult.INVALID;\n        }\n      } else {\n        if (!InstrumentUtils.isAssignable(\n            actionArgTypes[om.getTargetInstanceParameter()],\n            calledType,\n            cl,\n            om.isExactTypeMatch())) {\n          report(\n              \"Invalid @TargetInstance parameter. Expected \"\n                  + Constants.OBJECT_TYPE\n                  + \", received \"\n                  + actionArgTypes[om.getTargetInstanceParameter()]);\n          return ValidationResult.INVALID;\n        }\n      }\n      specialArgsCount++;\n    }\n    if (om.getDurationParameter() != -1) {\n      if (!actionArgTypes[om.getDurationParameter()].equals(Type.LONG_TYPE)) {\n        return ValidationResult.INVALID;\n      }\n      specialArgsCount++;\n    }\n    if (om.getClassNameParameter() != -1) {\n      if (!(InstrumentUtils.isAssignable(\n          actionArgTypes[om.getClassNameParameter()],\n          Constants.STRING_TYPE,\n          cl,\n          om.isExactTypeMatch()))) {\n        return ValidationResult.INVALID;\n      }\n      specialArgsCount++;\n    }\n    if (om.getMethodParameter() != -1) {\n      if (!(InstrumentUtils.isAssignable(\n          actionArgTypes[om.getMethodParameter()],\n          Constants.STRING_TYPE,\n          cl,\n          om.isExactTypeMatch()))) {\n        return ValidationResult.INVALID;\n      }\n      specialArgsCount++;\n    }\n\n    Type[] cleansedArgArray = new Type[actionArgTypes.length - specialArgsCount];\n    int[] cleansedArgIndex = new int[cleansedArgArray.length];\n\n    int counter = 0;\n    for (int argIndex = 0; argIndex < actionArgTypes.length; argIndex++) {\n      if (argIndex != om.getSelfParameter()\n          && argIndex != om.getClassNameParameter()\n          && argIndex != om.getMethodParameter()\n          && argIndex != om.getReturnParameter()\n          && argIndex != om.getTargetInstanceParameter()\n          && argIndex != om.getTargetMethodOrFieldParameter()\n          && argIndex != om.getDurationParameter()) {\n        cleansedArgArray[counter] = actionArgTypes[argIndex];\n        cleansedArgIndex[counter] = argIndex;\n        counter++;\n      }\n    }\n    if (cleansedArgArray.length == 0) {\n      return ValidationResult.ANY;\n    } else {\n      if (!TypeUtils.isAnyTypeArray(cleansedArgArray[0])\n          && !InstrumentUtils.isAssignable(\n              cleansedArgArray, methodArgTypes, cl, om.isExactTypeMatch())) {\n        return ValidationResult.INVALID;\n      }\n    }\n    return new ValidationResult(true, cleansedArgIndex);\n  }\n\n  private Label levelCheck(OnMethod om, String className, boolean saveResult) {\n    // Level checks moved to MethodHandle layer (HandlerRepositoryImpl.applyLevelGuard).\n    // No bytecode-level level guards are needed; the INVOKEDYNAMIC will execute\n    // unconditionally, and the linked MethodHandle will perform the level check.\n    return null;\n  }\n\n  protected Label levelCheck(OnMethod om, String className) {\n    return levelCheck(om, className, false);\n  }\n\n  protected Label levelCheckBefore(OnMethod om, String className) {\n    return levelCheck(om, className, om.getLocation().getWhere() == Where.AFTER);\n  }\n\n  protected Label levelCheckAfter(OnMethod om, String className) {\n    Label l = null;\n    if (levelCheckVar != Integer.MIN_VALUE) {\n      Level level = om.getLevel();\n      if (isLevelCheck(level)) {\n        l = new Label();\n        asm.loadLocal(Type.INT_TYPE, levelCheckVar).jump(IFLT, l);\n      }\n    } else {\n      l = levelCheck(om, className);\n    }\n    return l;\n  }\n\n  protected final boolean isPrologueVisited() {\n    return prologueVisited;\n  }\n\n  private void report(String msg) {\n    String out = \"[\" + getName(true) + \"] \" + msg;\n    if (Boolean.getBoolean(\"btrace.validation.warn\")) {\n      log.warn(out);\n    } else if (Boolean.getBoolean(\"btrace.validation.info\")) {\n      log.info(out);\n    } else {\n      log.debug(out);\n    }\n  }\n\n  protected static final class ValidationResult {\n    private static final int[] EMPTY_ARRAY = new int[0];\n    protected static final ValidationResult INVALID = new ValidationResult(false);\n    protected static final ValidationResult ANY = new ValidationResult(true);\n    private final boolean isValid;\n    private final int[] argsIndex;\n\n    public ValidationResult(boolean valid, int[] argsIndex) {\n      this.isValid = valid;\n      this.argsIndex = java.util.Objects.requireNonNull(argsIndex, \"argsIndex must not be null\");\n    }\n\n    public ValidationResult(boolean valid) {\n      this(valid, EMPTY_ARRAY);\n    }\n\n    public int getArgIdx(int ptr) {\n      return ptr > -1 && ptr < argsIndex.length ? argsIndex[ptr] : -1;\n    }\n\n    public int getArgCnt() {\n      return argsIndex.length;\n    }\n\n    public boolean isAny() {\n      return isValid && argsIndex.length == 0;\n    }\n\n    public boolean isValid() {\n      return isValid;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n      if (obj == null) {\n        return false;\n      }\n      if (getClass() != obj.getClass()) {\n        return false;\n      }\n      ValidationResult other = (ValidationResult) obj;\n      if (isValid != other.isValid) {\n        return false;\n      }\n      return Arrays.equals(argsIndex, other.argsIndex);\n    }\n\n    @Override\n    public int hashCode() {\n      int hash = 5;\n      hash = 59 * hash + (isValid ? 1 : 0);\n      hash = 59 * hash + Arrays.hashCode(argsIndex);\n      return hash;\n    }\n  }\n\n  public abstract static class ArgumentProvider {\n    static final Comparator<ArgumentProvider> COMPARATOR =\n        (o1, o2) -> {\n          if (o1 == null && o2 == null) {\n            return 0;\n          }\n          if (o1 != null && o2 == null) return -1;\n          if (o1 == null) return 1;\n\n          if (o1.index == o2.index) {\n            return 0;\n          }\n          if (o1.index < o2.index) {\n            return -1;\n          }\n          return 1;\n        };\n    protected final Assembler asm;\n    private final int index;\n\n    public ArgumentProvider(Assembler asm, int index) {\n      this.index = index;\n      this.asm = asm;\n    }\n\n    public int getIndex() {\n      return index;\n    }\n\n    public final void provide() {\n      if (index > -1) {\n        doProvide();\n      }\n    }\n\n    protected abstract void doProvide();\n  }\n\n  private static class LocalVarArgProvider extends ArgumentProvider {\n    private final Type type;\n    private final int ptr;\n    private final boolean boxValue;\n\n    public LocalVarArgProvider(Assembler asm, int index, Type type, int ptr) {\n      this(asm, index, type, ptr, false);\n    }\n\n    public LocalVarArgProvider(Assembler asm, int index, Type type, int ptr, boolean boxValue) {\n      super(asm, index);\n      this.type = type;\n      this.ptr = ptr;\n      this.boxValue = boxValue;\n    }\n\n    @Override\n    public void doProvide() {\n      asm.loadLocal(type, ptr);\n      if (boxValue) {\n        asm.box(type);\n      }\n    }\n\n    @Override\n    public String toString() {\n      return \"LocalVar #\" + ptr + \" of type \" + type + \" (@\" + getIndex() + \")\";\n    }\n  }\n\n  private static class ConstantArgProvider extends ArgumentProvider {\n    private final Object constant;\n\n    public ConstantArgProvider(Assembler asm, int index, Object constant) {\n      super(asm, index);\n      this.constant = constant;\n    }\n\n    @Override\n    public void doProvide() {\n      asm.ldc(constant);\n    }\n\n    @Override\n    public String toString() {\n      return \"Constant \" + constant + \" (@\" + getIndex() + \")\";\n    }\n  }\n\n  protected class AnyTypeArgProvider extends ArgumentProvider {\n    private int argPtr;\n    private final Type[] myArgTypes;\n\n    public AnyTypeArgProvider(Assembler asm, int index, int basePtr) {\n      this(asm, index, basePtr, argumentTypes);\n    }\n\n    public AnyTypeArgProvider(Assembler asm, int index, int basePtr, Type[] argTypes) {\n      super(asm, index);\n      argPtr = basePtr;\n      myArgTypes = argTypes;\n    }\n\n    @Override\n    public void doProvide() {\n      asm.push(myArgTypes.length);\n      asm.newArray(Constants.OBJECT_TYPE);\n      for (int j = 0; j < myArgTypes.length; j++) {\n        Type argType = myArgTypes[j];\n        asm.dup().push(j).loadLocal(argType, argPtr).box(argType).arrayStore(Constants.OBJECT_TYPE);\n        argPtr += argType.getSize();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodInstrumentorHelper.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport java.util.function.Supplier;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.Type;\n\npublic interface MethodInstrumentorHelper {\n  void insertFrameReplaceStack(Label l, Type... stack);\n\n  void insertFrameAppendStack(Label l, Type... stack);\n\n  void insertFrameSameStack(Label l);\n\n\n  void addTryCatchHandler(Label start, Label handler);\n\n  int newVar(Type t);\n\n  int storeAsNew();\n\n  /**\n   * Get or create a MethodTrackingContext for the given method ID.\n   * Ensures multiple instrumentors for the same method share the same context.\n   *\n   * @param methodId unique method identifier\n   * @param factory supplier to create new context if needed\n   * @return shared MethodTrackingContext instance\n   */\n  MethodTrackingContext getOrCreateTrackingContext(\n      int methodId, Supplier<MethodTrackingContext> factory);\n\n  /**\n   * Returns whether level variable caching should be used.\n   * Caching is only needed when multiple handlers require level checks.\n   *\n   * @return true if level variable should be cached, false otherwise\n   */\n  boolean shouldCacheLevelVar();\n\n  interface Accessor {\n    MethodInstrumentorHelper methodHelper();\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodReturnInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * This visitor helps in inserting code whenever a method call returns. The code to insert on method\n * return may be decided by derived class. By default, this class inserts code to print name and\n * signature of the method returned.\n *\n * @author A. Sundararajan\n */\npublic class MethodReturnInstrumentor extends MethodEntryInstrumentor {\n  public MethodReturnInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  public void visitInsn(int opcode) {\n    switch (opcode) {\n      case IRETURN:\n      case ARETURN:\n      case FRETURN:\n      case LRETURN:\n      case DRETURN:\n      case RETURN:\n        onMethodReturn(opcode);\n        break;\n      default:\n        break;\n    }\n    super.visitInsn(opcode);\n  }\n\n  protected void onMethodReturn(int opcode) {\n    asm.println(\"leaving \" + getName() + getDescriptor());\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodTracker.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport java.util.Arrays;\nimport java.util.concurrent.atomic.AtomicLong;\nimport org.openjdk.btrace.core.MethodID;\n\n/**\n * Provides a centralized place to track the fundamental metrics for method execution. It is mostly\n * called from the injected code to support sampling and timing.\n *\n * @author Jaroslav Bachorik\n */\npublic final class MethodTracker {\n  private static final RandomIntProvider rndIntProvider = RandomIntProvider.getInstance();\n\n  private static AtomicLong[] counters = new AtomicLong[50];\n\n  @SuppressWarnings(\"unchecked\")\n  private static ThreadLocal<Long>[] tsArray = new ThreadLocal[50];\n\n  private static Object[] rLocks = new Object[50];\n  private static int[] means = new int[50];\n  private static int[] origMeans = new int[50];\n  private static int[] samplers = new int[50];\n\n  /**\n   * Creates a supporting structures for a new method id\n   *\n   * @param methodId The method id - generated by the {@linkplain MethodID} class\n   * @param mean The sampler mean or 0 if not applicable\n   */\n  public static synchronized void registerCounter(int methodId, int mean) {\n    if (counters.length <= methodId) {\n      int newLen = methodId * 2;\n      counters = Arrays.copyOf(counters, newLen);\n      rLocks = Arrays.copyOf(rLocks, newLen);\n      means = Arrays.copyOf(means, newLen);\n      origMeans = Arrays.copyOf(origMeans, newLen);\n      samplers = Arrays.copyOf(samplers, newLen);\n      tsArray = Arrays.copyOf(tsArray, newLen);\n    }\n    if (counters[methodId] == null) {\n      counters[methodId] = new AtomicLong(0);\n      rLocks[methodId] = new Object();\n      means[methodId] = mean * 2;\n      origMeans[methodId] = mean;\n      tsArray[methodId] = ThreadLocal.withInitial(() -> 0L);\n      samplers[methodId] = 0;\n    }\n  }\n\n  /**\n   * Records the invocation of a certain method and indicates whether it should be traced or not\n   * (sampling). This method will be called when using the average sampling mode.\n   *\n   * @param methodId The method id - generated by the {@linkplain MethodID} class\n   * @return {@code true} if the invocation should be traced\n   */\n  public static boolean hit(int methodId) {\n    int mean = means[methodId];\n    if (mean == 0) {\n      return true;\n    }\n    AtomicLong l = counters[methodId];\n    if (l.getAndDecrement() <= 0) {\n      int inc = rndIntProvider.nextInt(mean) + 1;\n      l.addAndGet(inc);\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * Records the invocation of a certain method alongside the timestamp and indicates whether it\n   * should be traced or not (sampling). This method will be called when using the average sampling\n   * mode.\n   *\n   * @param methodId The method id - generated by the {@linkplain MethodID} class\n   * @return a positive number (invocation time stamp) if the invocation should be traced\n   */\n  public static long hitTimed(int methodId) {\n    int mean = means[methodId];\n    if (mean == 0) {\n      long ts = System.nanoTime();\n      tsArray[methodId].set(ts);\n      return ts;\n    }\n    AtomicLong l = counters[methodId];\n    if (l.getAndDecrement() <= 0) {\n      long ts = System.nanoTime();\n      int inc = rndIntProvider.nextInt(mean) + 1;\n      l.addAndGet(inc);\n      tsArray[methodId].set(ts);\n      return ts;\n    }\n    return 0L;\n  }\n\n  /**\n   * Records the invocation of a certain method and indicates whether it should be traced or not\n   * (sampling). This method will be called when using the adaptive sampling mode.\n   *\n   * @param methodId The method id - generated by the {@linkplain MethodID} class\n   * @return {@code true} if the invocation should be traced\n   */\n  public static boolean hitAdaptive(int methodId) {\n    AtomicLong cntr = counters[methodId];\n    int origMean = origMeans[methodId];\n    int mean = means[methodId];\n    if (cntr.getAndDecrement() <= 0) {\n      long ts = System.nanoTime();\n      ThreadLocal<Long> tsRef = tsArray[methodId];\n      long ts1 = tsRef.get();\n      if (ts1 != 0) {\n        long diff = ts - ts1;\n        if (mean < 1500 && diff < origMean) {\n          synchronized (rLocks[methodId]) {\n            means[methodId] = ++mean;\n          }\n        } else if (mean > 1 && diff > origMean) {\n          synchronized (rLocks[methodId]) {\n            means[methodId] = --mean;\n          }\n        }\n      }\n      tsRef.set(ts);\n\n      int inc = rndIntProvider.nextInt(mean) + 1;\n      cntr.addAndGet(inc);\n\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * Records the invocation of a certain method alongside the timestamp and indicates whether it\n   * should be traced or not (sampling). This method will be called when using the adaptive sampling\n   * mode.\n   *\n   * @param methodId The method id - generated by the {@linkplain MethodID} class\n   * @return a positive number (invocation time stamp) if the invocation should be traced\n   */\n  public static long hitTimedAdaptive(int methodId) {\n    AtomicLong cntr = counters[methodId];\n    int mean = means[methodId];\n    int origMean = origMeans[methodId];\n    if (cntr.getAndDecrement() <= 0) {\n      long ts = System.nanoTime();\n      ThreadLocal<Long> tsRef = tsArray[methodId];\n      long ts1 = tsRef.get();\n      if (ts1 != 0) {\n        long diff = ts - ts1;\n        if (mean < 1500 && diff < origMean) {\n          synchronized (rLocks[methodId]) {\n            means[methodId] = ++mean;\n          }\n        } else if (mean > 1 && diff > origMean) {\n          synchronized (rLocks[methodId]) {\n            means[methodId] = --mean;\n          }\n        }\n      }\n      tsRef.set(ts);\n\n      int inc = rndIntProvider.nextInt(mean) + 1;\n      cntr.addAndGet(inc);\n\n      return ts;\n    }\n    return 0L;\n  }\n\n  /**\n   * Used when timing the method execution or in adaptive sampling. To be used at the end of the\n   * sampled block.\n   *\n   * @param methodId The method id generated by {@linkplain MethodID} class\n   * @return The time stamp\n   */\n  public static long getEndTs(int methodId) {\n    long ts = System.nanoTime();\n    tsArray[methodId].set(ts);\n    return ts;\n  }\n\n  /**\n   * Used in adaptive sampling. To be used at the end of the sampled block.\n   *\n   * @param methodId The method id generated by {@linkplain MethodID} class\n   */\n  public static void updateEndTs(int methodId) {\n    tsArray[methodId].set(System.nanoTime());\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodTrackingContext.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.Type;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.instr.Constants;\nimport org.openjdk.btrace.runtime.Interval;\n\n/**\n * Context for emitting method tracking bytecode (sampling and timing). Replaces the template\n * system with direct bytecode generation.\n */\npublic class MethodTrackingContext {\n  private static final String METHOD_COUNTER_CLASS = \"org/openjdk/btrace/instr/MethodTracker\";\n\n  private final Assembler asm;\n  private final MethodInstrumentorHelper helper;\n  private final String probeClassName;\n  private final int baseMethodId;\n  private final org.objectweb.asm.MethodVisitor mv;\n\n  // Configuration (set via entry)\n  private boolean timed = false;\n  private boolean sampled = false;\n  private Sampled.Sampler samplerKind = Sampled.Sampler.None;\n  private int samplerMean = -1;\n\n  // State (per entry point)\n  private int entryTsVar = Integer.MIN_VALUE;\n  private int sHitVar = Integer.MIN_VALUE;\n  private int durationVar = Integer.MIN_VALUE;\n  private boolean durationComputed = false;\n  private boolean prologueEmitted = false;\n  private Label elseLabel = null;\n  private Label samplerLabel = null;\n\n  public MethodTrackingContext(\n      org.objectweb.asm.MethodVisitor mv,\n      Assembler asm,\n      MethodInstrumentorHelper helper,\n      String probeClassName,\n      int baseMethodId) {\n    this.mv = mv;\n    this.asm = asm;\n    this.helper = helper;\n    this.probeClassName = probeClassName;\n    this.baseMethodId = baseMethodId;\n  }\n\n  /**\n   * Emit entry bytecode for sampling/timing setup.\n   *\n   * @param timed whether to enable timing\n   * @param samplerKind sampler type (None, Const, Adaptive)\n   * @param samplerMean mean hits between samples\n   * @param methodId method ID for tracking\n   * @param levelStr level match condition\n   */\n  public void emitEntry(\n      boolean timed, Sampled.Sampler samplerKind, int samplerMean, int methodId, String levelStr) {\n    // Idempotence: ensure prologue emits only once for shared contexts\n    if (prologueEmitted) {\n      return;\n    }\n\n    this.timed = timed;\n    this.samplerKind = samplerKind;\n    this.samplerMean = samplerMean;\n    this.sampled = samplerKind != Sampled.Sampler.None && samplerMean > 0;\n\n    if (sampled) {\n      MethodTracker.registerCounter(methodId, samplerMean);\n      if (timed) {\n        emitTimingSamplerEntry(methodId);\n      } else {\n        emitSamplerEntry(methodId);\n      }\n    } else {\n      if (timed) {\n        emitTimingEntry();\n      }\n    }\n\n    prologueEmitted = true;\n  }\n\n  /**\n   * Emit test sample bytecode - generates branch logic for sampling condition.\n   *\n   * @param collectTime whether to collect timing information\n   * @param methodId method ID for tracking\n   */\n  public void emitTestSample(boolean collectTime, int methodId) {\n    samplerLabel = new Label();\n    boolean expanded = false;\n\n    if (sampled) {\n      emitSamplerTest();\n      if (timed && collectTime) {\n        emitTimingSamplerTest(methodId);\n      }\n      expanded = true;\n    } else {\n      if (timed && collectTime) {\n        emitTimingTest();\n        expanded = true;\n      }\n    }\n\n    if (expanded) {\n      asm.label(samplerLabel);\n      helper.insertFrameSameStack(samplerLabel);\n    }\n    samplerLabel = null;\n  }\n\n  /** Emit else label bytecode - jump target for non-sampled executions. */\n  public void emitElse() {\n    if (elseLabel != null) {\n      asm.label(elseLabel);\n      helper.insertFrameSameStack(elseLabel);\n      elseLabel = null;\n    }\n  }\n\n  /**\n   * Emit duration bytecode - pushes method execution duration onto stack.\n   *\n   * @return true if duration was computed, false if zero pushed\n   */\n  public boolean emitDuration() {\n    if (!durationComputed) {\n      asm.ldc(0L);\n      return false;\n    } else {\n      asm.loadLocal(Type.LONG_TYPE, durationVar);\n      return true;\n    }\n  }\n\n  /**\n   * Emit exit bytecode - update adaptive sampling statistics.\n   *\n   * @param methodId method ID for tracking\n   */\n  public void emitExit(int methodId) {\n    if (samplerKind == Sampled.Sampler.Adaptive) {\n      Label l = new Label();\n      asm.loadLocal(Type.INT_TYPE, sHitVar)\n          .jump(IFEQ, l)\n          .ldc(methodId)\n          .invokeStatic(METHOD_COUNTER_CLASS, \"updateEndTs\", \"(I)V\")\n          .label(l);\n      helper.insertFrameSameStack(l);\n    }\n  }\n\n  /** Reset state for multiple return points. */\n  public void reset() {\n    entryTsVar = Integer.MIN_VALUE;\n    sHitVar = Integer.MIN_VALUE;\n    durationComputed = false;\n  }\n\n  /** Reset only duration computation flag (for multiple error handlers). */\n  public void resetDuration() {\n    durationComputed = false;\n  }\n\n  /**\n   * Compute duration for error handlers - no level checks or sampling logic.\n   * Just computes nanoTime() - entryTs and stores to durationVar.\n   */\n  public void computeDurationForErrorHandler() {\n    if (!durationComputed) {\n      if (entryTsVar != Integer.MIN_VALUE) {\n        asm.invokeStatic(\"java/lang/System\", \"nanoTime\", \"()J\")\n            .loadLocal(Type.LONG_TYPE, entryTsVar)\n            .sub(Type.LONG_TYPE);\n      } else {\n        asm.ldc(0L);\n      }\n      if (durationVar == Integer.MIN_VALUE) {\n        durationVar = helper.storeAsNew();\n      } else {\n        asm.storeLocal(Type.LONG_TYPE, durationVar);\n      }\n      durationComputed = true;\n    }\n  }\n\n  // Private helper methods for bytecode generation\n\n  private void emitTimingSamplerEntry(int mid) {\n    if (durationVar == Integer.MIN_VALUE) {\n      asm.ldc(0L);\n      durationVar = helper.storeAsNew();\n    }\n\n    if (sHitVar == Integer.MIN_VALUE && entryTsVar == Integer.MIN_VALUE) {\n      Label skipTarget =\n          addLevelChecks(\n              () -> {\n                if (entryTsVar == Integer.MIN_VALUE) {\n                  asm.ldc(0L);\n                  entryTsVar = helper.storeAsNew();\n                }\n                if (sHitVar == Integer.MIN_VALUE) {\n                  asm.ldc(0);\n                  sHitVar = helper.storeAsNew();\n                }\n              });\n\n      asm.ldc(mid);\n      switch (samplerKind) {\n        case Const:\n          asm.invokeStatic(METHOD_COUNTER_CLASS, \"hitTimed\", \"(I)J\");\n          break;\n        case Adaptive:\n          asm.invokeStatic(METHOD_COUNTER_CLASS, \"hitTimedAdaptive\", \"(I)J\");\n          break;\n        default:\n          // do nothing\n      }\n\n      asm.dup2();\n      if (entryTsVar == Integer.MIN_VALUE) {\n        entryTsVar = helper.storeAsNew();\n      } else {\n        asm.storeLocal(Type.LONG_TYPE, entryTsVar);\n      }\n      mv.visitInsn(L2I);\n      if (sHitVar == Integer.MIN_VALUE) {\n        sHitVar = helper.storeAsNew();\n      } else {\n        asm.storeLocal(Type.INT_TYPE, sHitVar);\n      }\n\n      if (skipTarget != null) {\n        asm.label(skipTarget);\n        helper.insertFrameSameStack(skipTarget);\n      }\n    }\n  }\n\n  private void emitSamplerEntry(int mid) {\n    if (sHitVar == Integer.MIN_VALUE) {\n      Label skipTarget =\n          addLevelChecks(\n              () -> {\n                if (sHitVar == Integer.MIN_VALUE) {\n                  asm.ldc(0);\n                  sHitVar = helper.storeAsNew();\n                }\n              });\n\n      asm.ldc(mid);\n      switch (samplerKind) {\n        case Const:\n          asm.invokeStatic(METHOD_COUNTER_CLASS, \"hit\", \"(I)Z\");\n          break;\n        case Adaptive:\n          asm.invokeStatic(METHOD_COUNTER_CLASS, \"hitAdaptive\", \"(I)Z\");\n          break;\n        default:\n          // do nothing\n      }\n\n      if (sHitVar == Integer.MIN_VALUE) {\n        sHitVar = helper.storeAsNew();\n      } else {\n        asm.storeLocal(Type.INT_TYPE, sHitVar);\n      }\n\n      if (skipTarget != null) {\n        asm.label(skipTarget);\n        helper.insertFrameSameStack(skipTarget);\n      }\n    }\n  }\n\n  private void emitTimingEntry() {\n    if (entryTsVar == Integer.MIN_VALUE) {\n      if (durationVar == Integer.MIN_VALUE) {\n        asm.ldc(0L);\n        durationVar = helper.storeAsNew();\n      }\n\n      Label skipTarget =\n          addLevelChecks(\n              () -> {\n                asm.ldc(0L);\n                entryTsVar = helper.storeAsNew();\n              });\n\n      asm.invokeStatic(\"java/lang/System\", \"nanoTime\", \"()J\");\n      if (entryTsVar == Integer.MIN_VALUE) {\n        entryTsVar = helper.storeAsNew();\n      } else {\n        asm.storeLocal(Type.LONG_TYPE, entryTsVar);\n      }\n\n      if (skipTarget != null) {\n        asm.label(skipTarget);\n        helper.insertFrameSameStack(skipTarget);\n      }\n    }\n  }\n\n  private void emitSamplerTest() {\n    if (sHitVar != Integer.MIN_VALUE) {\n      elseLabel = new Label();\n      addLevelChecks(samplerLabel);\n      asm.loadLocal(Type.INT_TYPE, sHitVar).jump(IFEQ, elseLabel);\n    }\n  }\n\n  private void emitTimingSamplerTest(int mid) {\n    if (!durationComputed) {\n      if (entryTsVar != Integer.MIN_VALUE) {\n        asm.ldc(mid)\n            .invokeStatic(METHOD_COUNTER_CLASS, \"getEndTs\", \"(I)J\")\n            .loadLocal(Type.LONG_TYPE, entryTsVar)\n            .sub(Type.LONG_TYPE);\n      } else {\n        asm.ldc(0L);\n      }\n      asm.storeLocal(Type.LONG_TYPE, durationVar);\n      durationComputed = true;\n    }\n  }\n\n  private void emitTimingTest() {\n    if (!durationComputed) {\n      addLevelChecks(samplerLabel);\n      if (entryTsVar != Integer.MIN_VALUE) {\n        asm.invokeStatic(\"java/lang/System\", \"nanoTime\", \"()J\")\n            .loadLocal(Type.LONG_TYPE, entryTsVar)\n            .sub(Type.LONG_TYPE);\n      } else {\n        asm.ldc(0L);\n      }\n      asm.storeLocal(Type.LONG_TYPE, durationVar);\n      durationComputed = true;\n    }\n  }\n\n  private Label addLevelChecks(Label skip) {\n    return addLevelChecks(skip, null);\n  }\n\n  private Label addLevelChecks(Runnable initializer) {\n    return addLevelChecks(null, initializer);\n  }\n\n  private Label addLevelChecks(Label skip, Runnable initializer) {\n    // Level checks moved to MethodHandle layer (HandlerRepositoryImpl.applyLevelGuard)\n    // No bytecode-level guards needed; INVOKEDYNAMIC always executes, and the linked\n    // MethodHandle performs the level check before invoking the real handler.\n    if (initializer != null) {\n      initializer.run();\n    }\n    return skip;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodVerifier.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.Type;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.extensions.Extension;\n\n/**\n * This class verifies that the BTrace \"action\" method is safe - boundedness and read-only rules are\n * checked such as no backward jumps (loops), no throw/new/invoke etc.\n *\n * @author A. Sundararajan\n */\nfinal class MethodVerifier extends StackTrackingMethodVisitor {\n  private static final Set<String> PRIMITIVE_WRAPPER_TYPES;\n  private static final Set<String> UNBOX_METHODS;\n\n  static {\n    PRIMITIVE_WRAPPER_TYPES = new HashSet<>();\n    UNBOX_METHODS = new HashSet<>();\n\n    PRIMITIVE_WRAPPER_TYPES.add(\"java/lang/Boolean\");\n    PRIMITIVE_WRAPPER_TYPES.add(\"java/lang/Byte\");\n    PRIMITIVE_WRAPPER_TYPES.add(\"java/lang/Character\");\n    PRIMITIVE_WRAPPER_TYPES.add(\"java/lang/Short\");\n    PRIMITIVE_WRAPPER_TYPES.add(\"java/lang/Integer\");\n    PRIMITIVE_WRAPPER_TYPES.add(\"java/lang/Long\");\n    PRIMITIVE_WRAPPER_TYPES.add(\"java/lang/Float\");\n    PRIMITIVE_WRAPPER_TYPES.add(\"java/lang/Double\");\n    UNBOX_METHODS.add(\"booleanValue\");\n    UNBOX_METHODS.add(\"byteValue\");\n    UNBOX_METHODS.add(\"charValue\");\n    UNBOX_METHODS.add(\"shortValue\");\n    UNBOX_METHODS.add(\"intValue\");\n    UNBOX_METHODS.add(\"longValue\");\n    UNBOX_METHODS.add(\"floatValue\");\n    UNBOX_METHODS.add(\"doubleValue\");\n  }\n\n  private final String className;\n  private final String methodName;\n  private final String methodDesc;\n  private final int access;\n  private final Map<Label, Label> labels;\n  private Object delayedClzLoad = null;\n\n  public MethodVerifier(\n      BTraceMethodNode parent,\n      int access,\n      String className,\n      String methodName,\n      String desc,\n      ClassLoader ctxClassLoader) {\n    super(parent, className, desc, ((access & ACC_STATIC) == ACC_STATIC));\n    this.className = className;\n    this.methodName = methodName;\n    methodDesc = desc;\n    this.access = access;\n    labels = new HashMap<>();\n  }\n\n  static boolean isPrimitiveWrapper(String type) {\n    return PRIMITIVE_WRAPPER_TYPES.contains(type);\n  }\n\n  static boolean isUnboxMethod(String name) {\n    return UNBOX_METHODS.contains(name);\n  }\n\n  private BTraceMethodNode getParent() {\n    return (BTraceMethodNode) mv;\n  }\n\n  @Override\n  public void visitEnd() {\n    super.visitEnd();\n    if (getParent().isBTraceHandler()) { // only btrace handlers are enforced to be public\n      if ((access & ACC_PUBLIC) == 0 && !methodName.equals(Constants.CLASS_INITIALIZER)) {\n        Verifier.reportError(\"method.should.be.public\", methodName + methodDesc);\n      }\n      if (!Type.getReturnType(methodDesc).equals(Type.VOID_TYPE)) {\n        Verifier.reportError(\"return.type.should.be.void\", methodName + methodDesc);\n      }\n    }\n    validateSamplerLocation();\n    labels.clear();\n  }\n\n  @Override\n  public void visitFieldInsn(int opcode, String owner, String name, String desc) {\n    if (opcode == PUTFIELD) {\n      Verifier.reportError(\"no.assignment\");\n    }\n\n    if (opcode == PUTSTATIC) {\n      if (!owner.equals(className)) {\n        Verifier.reportError(\"no.assignment\");\n      }\n    }\n    super.visitFieldInsn(opcode, owner, name, desc);\n  }\n\n  @Override\n  public void visitInsn(int opcode) {\n    switch (opcode) {\n      case IASTORE:\n      case LASTORE:\n      case FASTORE:\n      case DASTORE:\n      case AASTORE:\n      case BASTORE:\n      case CASTORE:\n      case SASTORE:\n        Verifier.reportError(\"no.assignment\");\n        break;\n      case ATHROW:\n        Verifier.reportError(\"no.throw\");\n        break;\n      case MONITORENTER:\n      case MONITOREXIT:\n        Verifier.reportError(\"no.synchronized.blocks\");\n        break;\n    }\n    super.visitInsn(opcode);\n  }\n\n  @Override\n  public void visitIntInsn(int opcode, int operand) {\n    if (opcode == NEWARRAY) {\n      Verifier.reportError(\"no.array.creation\");\n    }\n    super.visitIntInsn(opcode, operand);\n  }\n\n  @Override\n  public void visitJumpInsn(int opcode, Label label) {\n    if (labels.get(label) != null) {\n      Verifier.reportError(\"no.loops\");\n    }\n    super.visitJumpInsn(opcode, label);\n  }\n\n  @Override\n  public void visitLabel(Label label) {\n    labels.put(label, label);\n    super.visitLabel(label);\n  }\n\n  @Override\n  public void visitLdcInsn(Object cst) {\n    if (cst instanceof Type) {\n      delayedClzLoad = cst;\n    }\n    super.visitLdcInsn(cst);\n  }\n\n  @Override\n  public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {\n    if (!isJfrEventType(owner)) {\n      switch (opcode) {\n        case INVOKEVIRTUAL:\n          if (isPrimitiveWrapper(owner) && isUnboxMethod(name)) {\n            // allow primitive type unbox methods.\n            // These calls are generated by javac for auto-unboxing\n            // and can't be caught by source AST analyzer as well.\n          } else if (owner.equals(Type.getInternalName(StringBuilder.class))) {\n            // allow string concatenation via StringBuilder\n          } else {\n            List<StackItem> args = getMethodParams(desc, false);\n            // Allow calls on service targets or service-derived types (return types from services)\n            // This makes the verifier cooperate with the extension system automatically\n            if (!isServiceTarget(args.get(0)) && !getParent().isServiceType(owner)) {\n              Verifier.reportError(\"no.method.calls\", owner + \".\" + name + desc);\n            }\n          }\n          break;\n        case INVOKEINTERFACE:\n          // Allow interface calls on service-derived types\n          if (!getParent().isServiceType(owner)) {\n            Verifier.reportError(\"no.method.calls\", owner + \".\" + name + desc);\n          }\n          break;\n        case INVOKESPECIAL:\n          if (owner.equals(Constants.OBJECT_INTERNAL) && name.equals(Constants.CONSTRUCTOR)) {\n            // allow object initializer\n          } else if (owner.equals(Type.getInternalName(StringBuilder.class))) {\n            // allow string concatenation via StringBuilder\n          } else {\n            Verifier.reportError(\"no.method.calls\", owner + \".\" + name + desc);\n          }\n          break;\n        case INVOKESTATIC:\n          if (!owner.equals(Constants.BTRACE_UTILS)\n              && !owner.startsWith(Constants.BTRACE_UTILS + \"$\")\n              && !owner.equals(className)) {\n            if (\"valueOf\".equals(name) && isPrimitiveWrapper(owner)) {\n              // allow primitive wrapper boxing methods.\n              // These calls are generated by javac for autoboxing\n              // and can't be caught sourc AST analyzer as well.\n            } else {\n              Verifier.reportError(\"no.method.calls\", owner + \".\" + name + desc);\n            }\n          }\n          break;\n      }\n    }\n    if (delayedClzLoad != null) {\n      Verifier.reportError(\"no.class.literals\", delayedClzLoad.toString());\n    }\n    super.visitMethodInsn(opcode, owner, name, desc, itf);\n  }\n\n  @Override\n  public void visitMultiANewArrayInsn(String desc, int dims) {\n    Verifier.reportError(\"no.array.creation\");\n  }\n\n  @Override\n  public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {\n    Verifier.reportError(\"no.catch\");\n  }\n\n  @Override\n  public void visitTypeInsn(int opcode, String desc) {\n    if (opcode == ANEWARRAY) {\n      Verifier.reportError(\"no.array.creation\", desc);\n    }\n    if (opcode == NEW) {\n      // allow StringBuilder creation for string concatenation\n      if (desc.equals(Type.getInternalName(StringBuilder.class))) {\n        super.visitTypeInsn(NEW, desc);\n        return;\n      }\n      Verifier.reportError(\"no.new.object\", desc);\n    }\n    super.visitTypeInsn(opcode, desc);\n  }\n\n  @Override\n  public void visitVarInsn(int opcode, int var) {\n    if (opcode == RET) {\n      Verifier.reportError(\"no.try\");\n    }\n    super.visitVarInsn(opcode, var);\n  }\n\n  private boolean isServiceTarget(StackItem si) {\n    if (si instanceof ResultItem) {\n      ResultItem ri = (ResultItem) si;\n      if (ri.getOwner().equals(className) && getParent().isFieldInjected(ri.getName())) {\n        return true;\n      }\n    }\n    for (StackItem p : si.getParents()) {\n      if (isServiceTarget(p)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private boolean isExtensionTarget(StackItem si) {\n    if (si instanceof ResultItem) {\n      ResultItem ri = (ResultItem) si;\n      if (ri.getOwner().equals(Type.getInternalName(Extension.class))) {\n        return true;\n      } else if (ri.getOwner().equals(className) && getParent().isFieldInjected(ri.getName())) {\n        return true;\n      }\n    }\n    for (StackItem p : si.getParents()) {\n      if (isExtensionTarget(p)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private void validateSamplerLocation() {\n    BTraceMethodNode mn = getParent();\n    // if not sampled just return\n    if (!mn.isSampled()) return;\n\n    OnMethod om = mn.getOnMethod();\n    if (om == null && mn.isSampled()) {\n      Verifier.reportError(\"sampler.invalid.location\", methodName + methodDesc);\n      return;\n    }\n    if (om != null && om.getSamplerKind() != Sampled.Sampler.None) {\n      switch (om.getLocation().getValue()) {\n        case ENTRY:\n        case RETURN:\n        case ERROR:\n        case CALL:\n          {\n            // ok\n            break;\n          }\n        default:\n          {\n            Verifier.reportError(\"sampler.invalid.location\", methodName + methodDesc);\n          }\n      }\n    }\n  }\n\n  private boolean isJfrEventType(String typeName) {\n    return \"org/openjdk/btrace/core/jfr/JfrEvent\".equals(typeName);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ObjectAllocInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.NEW;\n\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * This visitor helps in inserting code whenever an object is allocated. The code to insert on\n * object alloc may be decided by derived class. By default, this class inserts code to print a\n * message.\n *\n * @author A. Sundararajan\n */\npublic class ObjectAllocInstrumentor extends MethodInstrumentor {\n  private final boolean needsInitialization;\n  private boolean instanceCreated = false;\n\n  public ObjectAllocInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    this(cl, mv, mHelper, parentClz, superClz, access, name, desc, false);\n  }\n\n  public ObjectAllocInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc,\n      boolean needsInitialization) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n    this.needsInitialization = needsInitialization;\n  }\n\n  @Override\n  public void visitTypeInsn(int opcode, String desc) {\n    if (opcode == NEW) {\n      beforeObjectNew(desc);\n    }\n    super.visitTypeInsn(opcode, desc);\n    if (opcode == NEW) {\n      if (needsInitialization) {\n        instanceCreated = true;\n      } else {\n        afterObjectNew(desc);\n      }\n    }\n  }\n\n  @Override\n  public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean iface) {\n    super.visitMethodInsn(opcode, owner, name, desc, iface);\n    if (instanceCreated) {\n      if (Constants.CONSTRUCTOR.equals(name)) {\n        instanceCreated = false;\n        afterObjectNew(owner);\n      }\n    }\n  }\n\n  protected void beforeObjectNew(String desc) {}\n\n  protected void afterObjectNew(String desc) {}\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/OnMethod.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n * Copyright (c) 2017, 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.concurrent.atomic.AtomicReferenceFieldUpdater;\nimport java.util.regex.Pattern;\nimport java.util.regex.PatternSyntaxException;\n\n/**\n * This class is used to store data of the annotation OnMethod. We can not read the OnMethod\n * annotation using reflection API [because we strip {@code @OnMethod} annotated methods before\n * defineClass]. Instead, we read OnMethod annotation while parsing the BTrace class and store the\n * data in an instance of this class. Please note that the get/set methods have to be in sync with\n * OnMethod annotation.\n *\n * @author A. Sundararajan\n */\npublic final class OnMethod extends SpecialParameterHolder {\n  private static final Logger log = LoggerFactory.getLogger(OnMethod.class);\n\n  private String clazz;\n  private volatile Pattern compiledClassPattern;\n  private static final AtomicReferenceFieldUpdater<OnMethod, Pattern> compiledClassPatternUpdater = AtomicReferenceFieldUpdater.newUpdater(OnMethod.class, Pattern.class, \"compiledClassPattern\");\n  private String method = \"\";\n  private boolean exactTypeMatch;\n  private String type = \"\";\n  private Location loc = new Location();\n  // target method name on which this annotation is specified\n  private String targetName;\n  // target method descriptor on which this annotation is specified\n  private String targetDescriptor;\n  private boolean classRegexMatcher = false;\n  private boolean methodRegexMatcher = false;\n  private boolean classAnnotationMatcher = false;\n  private boolean methodAnnotationMatcher = false;\n  private boolean subtypeMatcher = false;\n  private int samplerMean = 0;\n  private Sampled.Sampler samplerKind = Sampled.Sampler.None;\n  private Level level = null;\n  private boolean isCalled = false;\n  private BTraceMethodNode bmn;\n\n  public OnMethod() {\n    // need this to deserialize from the probe descriptor\n  }\n\n  public OnMethod(BTraceMethodNode bmn) {\n    this.bmn = bmn;\n  }\n\n  public void copyFrom(OnMethod other) {\n    super.copyFrom(other);\n    setClazz(other.getClazz());\n    setMethod(other.getMethod());\n    setExactTypeMatch(other.isExactTypeMatch());\n    setType(other.getType());\n    setLocation(other.getLocation());\n    setLevel(other.getLevel());\n  }\n\n  public String getClazz() {\n    return clazz;\n  }\n\n  public void setClazz(String clazz) {\n    if (clazz.charAt(0) == '+') {\n      subtypeMatcher = true;\n      clazz = clazz.substring(1);\n    } else {\n      subtypeMatcher = false;\n      if (clazz.charAt(0) == '@') {\n        classAnnotationMatcher = true;\n        clazz = clazz.substring(1);\n      } else {\n        classAnnotationMatcher = false;\n      }\n      if (clazz.charAt(0) == '/' && Constants.REGEX_SPECIFIER.matcher(clazz).matches()) {\n        classRegexMatcher = true;\n        clazz = clazz.substring(1, clazz.length() - 1);\n      } else {\n        classRegexMatcher = false;\n      }\n    }\n    this.clazz = clazz;\n    this.compiledClassPattern = null;\n  }\n\n  public Pattern getClassPattern() {\n    if (!classRegexMatcher) {\n      return null;\n    }\n\n    if (compiledClassPattern == null) {\n      compiledClassPatternUpdater.updateAndGet(this, pattern -> {\n        if (pattern == null) {\n          try {\n            pattern = Pattern.compile(clazz);\n          } catch (PatternSyntaxException e) {\n            log.warn(\"Invalid regex pattern in OnMethod: {}, defaulting to '.*\", clazz, e);\n            pattern = Pattern.compile(\".*\");\n          }\n        }\n        return pattern;\n      });\n    }\n\n    return compiledClassPattern;\n  }\n\n  public String getMethod() {\n    return method;\n  }\n\n  public void setMethod(String method) {\n    char firstChar = method.isEmpty() ? 0 : method.charAt(0);\n    if (firstChar == '@') {\n      methodAnnotationMatcher = true;\n      method = method.substring(1);\n    } else {\n      methodAnnotationMatcher = false;\n    }\n    firstChar = method.isEmpty() ? 0 : method.charAt(0);\n    if (firstChar == '/' && Constants.REGEX_SPECIFIER.matcher(method).matches()) {\n      methodRegexMatcher = true;\n      method = method.substring(1, method.length() - 1);\n    } else {\n      methodRegexMatcher = false;\n    }\n    this.method = method;\n  }\n\n  public boolean isExactTypeMatch() {\n    return exactTypeMatch;\n  }\n\n  public void setExactTypeMatch(boolean exactTypeMatch) {\n    this.exactTypeMatch = exactTypeMatch;\n  }\n\n  public String getType() {\n    return type;\n  }\n\n  public void setType(String type) {\n    this.type = type;\n  }\n\n  public Location getLocation() {\n    return loc;\n  }\n\n  public void setLocation(Location loc) {\n    this.loc = loc;\n  }\n\n  public String getTargetName() {\n    return targetName;\n  }\n\n  public void setTargetName(String name) {\n    targetName = name;\n  }\n\n  public String getTargetDescriptor() {\n    return targetDescriptor;\n  }\n\n  public void setTargetDescriptor(String desc) {\n    targetDescriptor = desc;\n  }\n\n  public Sampled.Sampler getSamplerKind() {\n    return samplerKind;\n  }\n\n  public void setSamplerKind(Sampled.Sampler kind) {\n    samplerKind = kind;\n  }\n\n  public int getSamplerMean() {\n    return samplerMean;\n  }\n\n  public void setSamplerMean(int mean) {\n    samplerMean = mean;\n  }\n\n  public Level getLevel() {\n    return level;\n  }\n\n  public void setLevel(Level level) {\n    this.level = level;\n  }\n\n  public BTraceMethodNode getMethodNode() {\n    return bmn;\n  }\n\n  public boolean isClassRegexMatcher() {\n    return classRegexMatcher;\n  }\n\n  public boolean isMethodRegexMatcher() {\n    return methodRegexMatcher;\n  }\n\n  public boolean isClassAnnotationMatcher() {\n    return classAnnotationMatcher;\n  }\n\n  public boolean isMethodAnnotationMatcher() {\n    return methodAnnotationMatcher;\n  }\n\n  public boolean isSubtypeMatcher() {\n    return subtypeMatcher;\n  }\n\n  public boolean isCalled() {\n    return isCalled;\n  }\n\n  public void setCalled() {\n    isCalled = true;\n  }\n\n  @Override\n  public String toString() {\n    return \"OnMethod{\"\n        + \"clazz=\"\n        + clazz\n        + \", method=\"\n        + method\n        + \", type=\"\n        + type\n        + \", loc=\"\n        + loc\n        + \", targetName=\"\n        + targetName\n        + \", targetDescriptor=\"\n        + targetDescriptor\n        + \", classRegexMatcher=\"\n        + classRegexMatcher\n        + \", methodRegexMatcher=\"\n        + methodRegexMatcher\n        + \", classAnnotationMatcher=\"\n        + classAnnotationMatcher\n        + \", methodAnnotationMatcher=\"\n        + methodAnnotationMatcher\n        + \", subtypeMatcher=\"\n        + subtypeMatcher\n        + \", samplerMean=\"\n        + samplerMean\n        + \", samplerKind=\"\n        + samplerKind\n        + \", level=\"\n        + level\n        + \", bmn=\"\n        + bmn\n        + '}';\n  }\n\n  void applyArgs(ArgsMap argsMap) {\n    String value = getClazz();\n    if (!value.isEmpty()) {\n      String templated = argsMap.template(value);\n      if (!templated.equals(value)) {\n        setClazz(templated);\n      }\n    }\n    value = getMethod();\n    if (!value.isEmpty()) {\n      String templated = argsMap.template(value);\n      if (!templated.equals(value)) {\n        setMethod(templated);\n      }\n    }\n    value = getType();\n    if (!value.isEmpty()) {\n      String templated = argsMap.template(value);\n      if (!templated.equals(value)) {\n        setType(templated);\n      }\n    }\n    Location loc = getLocation();\n    value = loc.getClazz();\n    if (!value.isEmpty()) {\n      String templated = argsMap.template(value);\n      if (!templated.equals(value)) {\n        loc.setClazz(templated);\n      }\n    }\n    value = loc.getMethod();\n    if (!value.isEmpty()) {\n      String templated = argsMap.template(value);\n      if (!templated.equals(value)) {\n        loc.setMethod(templated);\n      }\n    }\n    value = loc.getField();\n    if (!value.isEmpty()) {\n      String templated = argsMap.template(value);\n      if (!templated.equals(value)) {\n        loc.setField(templated);\n      }\n    }\n    value = loc.getType();\n    if (!value.isEmpty()) {\n      String templated = argsMap.template(value);\n      if (!templated.equals(value)) {\n        loc.setType(templated);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/OnProbe.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport java.util.Collection;\nimport java.util.HashSet;\nimport javax.xml.bind.annotation.XmlAttribute;\nimport javax.xml.bind.annotation.XmlElement;\n\n/**\n * This class is used to store data of the annotation OnProbe. We can not read the OnMethod\n * annotation using reflection API [because we strip {@code @OnProbe} annotated methods before\n * defineClass]. Instead, we read OnProbe annotation while parsing the BTrace class and store the\n * data in an instance of this class. Please note that the get/set methods have to be in sync with\n * OnProbe annotation.\n *\n * @author A. Sundararajan\n */\npublic final class OnProbe extends SpecialParameterHolder {\n  private String namespace;\n  private String name;\n  // target method name on which this annotation is specified\n  private String targetName;\n  // target method descriptor on which this annotation is specified\n  private String targetDescriptor;\n  private Collection<OnMethod> onMethods;\n  private BTraceMethodNode bmn;\n\n  public OnProbe(BTraceMethodNode bmn) {\n    this.bmn = bmn;\n  }\n\n  public OnProbe() {\n    // need this to deserialize from the probe descriptor\n  }\n\n  @XmlAttribute\n  public String getNamespace() {\n    return namespace;\n  }\n\n  public void setNamespace(String namespace) {\n    this.namespace = namespace;\n  }\n\n  @XmlAttribute\n  public String getName() {\n    return name;\n  }\n\n  public void setName(String name) {\n    this.name = name;\n  }\n\n  public String getTargetName() {\n    return targetName;\n  }\n\n  public void setTargetName(String name) {\n    targetName = name;\n  }\n\n  public String getTargetDescriptor() {\n    return targetDescriptor;\n  }\n\n  public void setTargetDescriptor(String desc) {\n    targetDescriptor = desc;\n  }\n\n  @XmlElement(name = \"map\")\n  public Collection<OnMethod> getOnMethods() {\n    return onMethods;\n  }\n\n  public void setOnMethods(Collection<OnMethod> om) {\n    onMethods = om;\n  }\n\n  public void copyFrom(OnProbe other) {\n    super.copyFrom(other);\n    namespace = other.namespace;\n    name = other.name;\n    targetName = other.targetName;\n    targetDescriptor = other.targetDescriptor;\n    onMethods = new HashSet<>(other.onMethods);\n  }\n\n  public BTraceMethodNode getMethodNode() {\n    return bmn;\n  }\n\n  void setMethodNode(BTraceMethodNode bmn) {\n    this.bmn = bmn;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/Preprocessor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.Handle;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\nimport org.objectweb.asm.tree.AbstractInsnNode;\nimport org.objectweb.asm.tree.AnnotationNode;\nimport org.objectweb.asm.tree.ClassNode;\nimport org.objectweb.asm.tree.FieldInsnNode;\nimport org.objectweb.asm.tree.FieldNode;\nimport org.objectweb.asm.tree.FrameNode;\nimport org.objectweb.asm.tree.InsnList;\nimport org.objectweb.asm.tree.InsnNode;\nimport org.objectweb.asm.tree.InvokeDynamicInsnNode;\nimport org.objectweb.asm.tree.JumpInsnNode;\nimport org.objectweb.asm.tree.LabelNode;\nimport org.objectweb.asm.tree.LdcInsnNode;\nimport org.objectweb.asm.tree.MethodInsnNode;\nimport org.objectweb.asm.tree.MethodNode;\nimport org.objectweb.asm.tree.TryCatchBlockNode;\nimport org.objectweb.asm.tree.TypeInsnNode;\nimport org.objectweb.asm.tree.VarInsnNode;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.DebugSupport;\nimport org.openjdk.btrace.core.annotations.Event;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.extensions.Extension;\nimport org.openjdk.btrace.core.BTraceRuntimeBridge;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.invoke.CallSite;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.MethodType;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * This class preprocesses a compiled BTrace program. This is done after BTrace safety verification\n * but before instrumenting the probed classes.\n *\n * <p>Transformations done here:\n *\n * <p>1. add <clinit> method, if one not found 2. replace @Export fields by perf counters and\n * replace put/get by perf counter update/read 3. replace @TLS fields by ThreadLocal fields and\n * replace put/get by ThreadLocal set/get 4. In <clinit> method, add ThreadLocal creation and perf\n * counter creation calls (for @Export and\n *\n * @author A. Sundararajan\n * @author J. Bachorik (Tree API rewrite) @TLS fields respectively) 5. Add a field to store\n *     BTraceRuntime object and initialize the same in <clinit> method 6. add prolog and epilogue in\n *     each BTrace action method to insert BTraceRuntime.enter/leave and also to call\n *     BTraceRuntimeImplBase.handleException on exception catch 7. initialize and reference any\n *     service instances 8. add a field to store client's BTraceRuntime instance 9. make all fields\n *     publicly accessible\n */\nfinal class Preprocessor {\n  private static final Logger log = LoggerFactory.getLogger(Preprocessor.class);\n\n  private static final String ANNOTATIONS_PREFIX = \"org/openjdk/btrace/core/annotations/\";\n  private static final Type TLS_TYPE = Type.getType(\"L\" + ANNOTATIONS_PREFIX + \"TLS;\");\n  private static final Type EXPORT_TYPE = Type.getType(\"L\" + ANNOTATIONS_PREFIX + \"Export;\");\n  private static final Type INJECTED_TYPE = Type.getType(\"L\" + ANNOTATIONS_PREFIX + \"Injected;\");\n  private static final Type EVENT_TYPE = Type.getType(\"L\" + ANNOTATIONS_PREFIX + \"Event;\");\n  private static final String TIMERHANDLER_INTERNAL =\n      \"org/openjdk/btrace/core/handlers/TimerHandler\";\n  private static final String TIMERHANDLER_DESC = \"L\" + TIMERHANDLER_INTERNAL + \";\";\n  private static final String EVENTHANDLER_INTERNAL =\n      \"org/openjdk/btrace/core/handlers/EventHandler\";\n  private static final String EVENTHANDLER_DESC = \"L\" + EVENTHANDLER_INTERNAL + \";\";\n  private static final String ERRORHANDLER_INTERNAL =\n      \"org/openjdk/btrace/core/handlers/ErrorHandler\";\n  private static final String ERRORHANDLER_DESC = \"L\" + ERRORHANDLER_INTERNAL + \";\";\n  private static final String EXITHANDLER_INTERNAL = \"org/openjdk/btrace/core/handlers/ExitHandler\";\n  private static final String EXITHANDLER_DESC = \"L\" + EXITHANDLER_INTERNAL + \";\";\n  private static final String LOWMEMORYHANDLER_INTERNAL =\n      \"org/openjdk/btrace/core/handlers/LowMemoryHandler\";\n  private static final String LOWMEMORYHANDLER_DESC = \"L\" + LOWMEMORYHANDLER_INTERNAL + \";\";\n  private static final String NEW_TLS_DESC =\n      \"(\" + Constants.OBJECT_DESC + \")\" + Constants.THREAD_LOCAL_DESC;\n  private static final String TLS_SET_DESC =\n      \"(\" + Constants.OBJECT_DESC + \")\" + Constants.VOID_DESC;\n  private static final String TLS_GET_DESC = \"()\" + Constants.OBJECT_DESC;\n  private static final String NEW_PERFCOUNTER_DESC =\n      \"(\"\n          + Constants.OBJECT_DESC\n          + Constants.STRING_DESC\n          + Constants.STRING_DESC\n          + \")\"\n          + Constants.VOID_DESC;\n  private static final String BTRACERT_FOR_CLASS_DESC =\n      \"(\"\n          + Constants.CLASS_DESC\n          + \"[\"\n          + TIMERHANDLER_DESC\n          + \"[\"\n          + EVENTHANDLER_DESC\n          + \"[\"\n          + ERRORHANDLER_DESC\n          + \"[\"\n          + EXITHANDLER_DESC\n          + \"[\"\n          + LOWMEMORYHANDLER_DESC\n          + \")\"\n          + Constants.BTRACERTBRIDGE_DESC;\n  private static final String BTRACERT_ENTER_DESC =\n      \"(\" + Constants.BTRACERTBRIDGE_DESC + \")\" + Constants.BOOLEAN_DESC;\n  private static final String BTRACERT_HANDLE_EXCEPTION_DESC =\n      \"(\" + Constants.THROWABLE_DESC + \")\" + Constants.VOID_DESC;\n  private static final String RT_CTX_INTERNAL = \"org/openjdk/btrace/core/extensions/ExtensionContext\";\n  private static final String RT_CTX_DESC = \"L\" + RT_CTX_INTERNAL + \";\";\n  private static final Type RT_CTX_TYPE = Type.getType(RT_CTX_DESC);\n  private static final String RT_SERVICE_CTR_DESC = \"(\" + RT_CTX_DESC + \")V\";\n  private static final String SERVICE_CTR_DESC =\n      \"(\" + Constants.STRING_DESC + \")\" + Constants.VOID_DESC;\n\n  // Extension-related constants\n  private static final String GET_EXTENSION_DESC =\n      \"(\" + Constants.CLASS_DESC + \")\" + Constants.EXTENSION_DESC;\n\n  private static final String JFR_EVENT_TEMPLATE_INTERNAL =\n      \"org/openjdk/btrace/core/jfr/JfrEvent$Template\";\n  private static final String JFR_EVENT_TEMPLATE_DESC = \"L\" + JFR_EVENT_TEMPLATE_INTERNAL + \";\";\n  private static final String JFR_EVENT_TEMPLATE_FIELD_INTERNAL =\n      \"org/openjdk/btrace/core/jfr/JfrEvent$Template$Field\";\n  private static final String JFR_EVENT_TEMPLATE_FIELD_DESC =\n      \"L\" + JFR_EVENT_TEMPLATE_FIELD_INTERNAL + \";\";\n  private static final String JFR_EVENT_FACTORY_INTERNAL =\n      \"org/openjdk/btrace/core/jfr/JfrEvent$Factory\";\n  private static final String JFR_EVENT_FACTORY_DESC = \"L\" + JFR_EVENT_FACTORY_INTERNAL + \";\";\n\n  private static final Map<String, String> BOX_TYPE_MAP = new HashMap<>();\n  private static final Set<String> GUARDED_ANNOTS = new HashSet<>();\n  private static final Set<String> RT_AWARE_ANNOTS = new HashSet<>();\n  // For each @Export field, we create a perf counter\n  // with the name \"btrace.<class name>.<field name>\"\n  private static final String BTRACE_COUNTER_PREFIX = \"btrace.\";\n  private static final String JFR_HANDLER_FIELD_PREFIX = \"$jfr$handler$\";\n\n  static {\n    BOX_TYPE_MAP.put(\"I\", Constants.INTEGER_BOXED_DESC);\n    BOX_TYPE_MAP.put(\"S\", Constants.SHORT_BOXED_DESC);\n    BOX_TYPE_MAP.put(\"J\", Constants.LONG_BOXED_DESC);\n    BOX_TYPE_MAP.put(\"F\", Constants.FLOAT_BOXED_DESC);\n    BOX_TYPE_MAP.put(\"D\", Constants.DOUBLE_BOXED_DESC);\n    BOX_TYPE_MAP.put(\"B\", Constants.BYTE_BOXED_DESC);\n    BOX_TYPE_MAP.put(\"Z\", Constants.BOOLEAN_BOXED_DESC);\n    BOX_TYPE_MAP.put(\"C\", Constants.CHARACTER_BOXED_DESC);\n\n    RT_AWARE_ANNOTS.add(Constants.ONMETHOD_DESC);\n    RT_AWARE_ANNOTS.add(Constants.ONTIMER_DESC);\n    RT_AWARE_ANNOTS.add(Constants.ONEVENT_DESC);\n    RT_AWARE_ANNOTS.add(Constants.ONERROR_DESC);\n    RT_AWARE_ANNOTS.add(Constants.ONPROBE_DESC);\n    RT_AWARE_ANNOTS.add(Constants.JFRPERIODIC_DESC);\n\n    GUARDED_ANNOTS.addAll(RT_AWARE_ANNOTS);\n\n    // @OnExit is rtAware but not guarded\n    RT_AWARE_ANNOTS.add(Constants.ONEXIT_DESC);\n  }\n\n  private final Set<String> tlsFldNames = new HashSet<>();\n  private final Set<String> exportFldNames = new HashSet<>();\n  private final Set<String> jfrHandlerNames = new HashSet<>();\n  private final Map<String, AnnotationNode> eventFlds = new HashMap<>();\n  private final Map<String, AnnotationNode> injectedFlds = new HashMap<>();\n  private final Map<String, Integer> serviceLocals = new HashMap<>();\n  private MethodNode clinit = null;\n  private FieldNode rtField = null;\n\n  private final Map<MethodNode, EnumSet<MethodClassifier>> classifierMap = new HashMap<>();\n  private AbstractInsnNode clinitEntryPoint;\n  // Label marking where the <clinit> error handler should start (after runtime is set)\n  private LabelNode clinitErrorHandlerStart;\n\n  // Determines if the given ASM Type represents a class that is a BTrace Extension\n  private static boolean isExtensionType(Type implType, ClassLoader loader) {\n    if (implType == null) return false;\n    try {\n      Class<?> cls = Class.forName(implType.getClassName(), false, loader);\n      return Extension.class.isAssignableFrom(cls);\n    } catch (Throwable t) {\n      return false;\n    }\n  }\n\n  // Determines if the given type is an interface or abstract class\n  private static boolean isInterfaceOrAbstract(Type serviceType, ClassLoader loader) {\n    if (serviceType == null) return true;\n    try {\n      Class<?> cls = Class.forName(serviceType.getClassName(), false, loader);\n      int mod = cls.getModifiers();\n      return cls.isInterface() || java.lang.reflect.Modifier.isAbstract(mod);\n    } catch (Throwable t) {\n      // If unknown, prefer indy path for safety\n      return true;\n    }\n  }\n\n  public static AnnotationNode getAnnotation(FieldNode fn, Type annotation) {\n    if (fn == null || (fn.visibleAnnotations == null && fn.invisibleAnnotations == null))\n      return null;\n    String targetDesc = annotation.getDescriptor();\n    if (fn.visibleAnnotations != null) {\n      for (AnnotationNode an : fn.visibleAnnotations) {\n        if (an.desc.equals(targetDesc)) {\n          return an;\n        }\n      }\n    }\n    if (fn.invisibleAnnotations != null) {\n      for (AnnotationNode an : fn.invisibleAnnotations) {\n        if (an.desc.equals(targetDesc)) {\n          return an;\n        }\n      }\n    }\n    return null;\n  }\n\n  public static AnnotationNode getAnnotation(MethodNode mn, Type annotation) {\n    if (mn == null || mn.visibleAnnotations == null) return null;\n    String targetDesc = annotation.getDescriptor();\n    for (AnnotationNode an : mn.visibleAnnotations) {\n      if (an.desc.equals(targetDesc)) {\n        return an;\n      }\n    }\n    return null;\n  }\n\n  private static boolean isUnannotated(MethodNode mn) {\n    return mn == null || mn.visibleAnnotations == null || mn.visibleAnnotations.isEmpty();\n  }\n\n  @SuppressWarnings(\"unchecked\")\n  public void process(ClassNode cn) {\n    addLevelField(cn);\n    processClinit(cn);\n    processFields(cn);\n\n    for (MethodNode mn : getMethods(cn)) {\n      preprocessMethod(cn, mn);\n    }\n\n    InsnList eventsInit = initJfrEventFields(cn);\n    clinit.instructions.insertBefore(clinitEntryPoint, eventsInit);\n  }\n\n  @SuppressWarnings(\"unchecked\")\n  private InsnList initJfrEventFields(ClassNode cn) {\n    InsnList eventsInit = new InsnList();\n    for (Map.Entry<String, AnnotationNode> eventEntry : eventFlds.entrySet()) {\n      String fieldName = eventEntry.getKey();\n      AnnotationNode an = eventEntry.getValue();\n      String name = null;\n      String label = null;\n      String desc = null;\n      InsnList categoryLoad = null;\n      InsnList fieldsInit = null;\n      String handler = null;\n      String period = null;\n      boolean stacktrace = false;\n      Iterator<Object> iter = an.values.iterator();\n      while (iter.hasNext()) {\n        String key = (String) iter.next();\n        Object value = iter.next();\n        switch (key) {\n          case \"name\":\n            {\n              name = (String) value;\n              break;\n            }\n          case \"label\":\n            {\n              label = (String) value;\n              label = label.isEmpty() ? null : label;\n              break;\n            }\n          case \"description\":\n            {\n              desc = (String) value;\n              desc = desc.isEmpty() ? null : desc;\n              break;\n            }\n          case \"category\":\n            {\n              categoryLoad = loadEventCategory((List<String>) value);\n              break;\n            }\n          case \"fields\":\n            {\n              fieldsInit = loadEventFieldsDefs((List<AnnotationNode>) value);\n              break;\n            }\n          case \"stacktrace\":\n            {\n              stacktrace = (boolean) value;\n              break;\n            }\n          case \"period\":\n            {\n              period = (String) value;\n              period = period.isEmpty() ? null : period;\n              break;\n            }\n        }\n      }\n      if (fieldName.startsWith(JFR_HANDLER_FIELD_PREFIX)) {\n        handler = fieldName.substring(JFR_HANDLER_FIELD_PREFIX.length());\n        jfrHandlerNames.add(handler);\n      }\n      eventsInit.add(new TypeInsnNode(Opcodes.NEW, JFR_EVENT_TEMPLATE_INTERNAL));\n      eventsInit.add(new InsnNode(Opcodes.DUP));\n      eventsInit.add(new LdcInsnNode(cn.name.replace('/', '.')));\n      eventsInit.add(new LdcInsnNode(name));\n      eventsInit.add(label != null ? new LdcInsnNode(label) : new InsnNode(Opcodes.ACONST_NULL));\n      eventsInit.add(desc != null ? new LdcInsnNode(desc) : new InsnNode(Opcodes.ACONST_NULL));\n      if (categoryLoad != null) {\n        eventsInit.add(categoryLoad);\n      } else {\n        eventsInit.add(new InsnNode(Opcodes.ACONST_NULL));\n      }\n      if (fieldsInit != null) {\n        eventsInit.add(fieldsInit);\n      } else {\n        eventsInit.add(new InsnNode(Opcodes.ACONST_NULL));\n      }\n      eventsInit.add(new LdcInsnNode(stacktrace));\n      eventsInit.add(period != null ? new LdcInsnNode(period) : new InsnNode(Opcodes.ACONST_NULL));\n      eventsInit.add(\n          handler != null ? new LdcInsnNode(handler) : new InsnNode(Opcodes.ACONST_NULL));\n      eventsInit.add(\n          new MethodInsnNode(\n              Opcodes.INVOKESPECIAL,\n              JFR_EVENT_TEMPLATE_INTERNAL,\n              \"<init>\",\n              \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[\"\n                  + JFR_EVENT_TEMPLATE_FIELD_DESC\n                  + \"ZLjava/lang/String;Ljava/lang/String;)V\",\n              false));\n      eventsInit.add(\n          new MethodInsnNode(\n              Opcodes.INVOKESTATIC,\n              \"org/openjdk/btrace/core/BTraceRuntime\",\n              \"createEventFactory\",\n              \"(\" + JFR_EVENT_TEMPLATE_DESC + \")\" + JFR_EVENT_FACTORY_DESC,\n              false));\n      eventsInit.add(\n          new FieldInsnNode(\n              Opcodes.PUTSTATIC,\n              cn.name,\n              eventEntry.getKey(),\n              \"Lorg/openjdk/btrace/core/jfr/JfrEvent$Factory;\"));\n    }\n    return eventsInit;\n  }\n\n  private InsnList loadEventCategory(List<String> values) {\n    if (values == null) {\n      return null;\n    }\n\n    InsnList insn = new InsnList();\n    insn.add(new LdcInsnNode(values.size()));\n    insn.add(new TypeInsnNode(Opcodes.ANEWARRAY, Constants.STRING_INTERNAL));\n    int cntr = 0;\n    for (String value : values) {\n      insn.add(new InsnNode(Opcodes.DUP));\n      insn.add(new LdcInsnNode(cntr++));\n      insn.add(new LdcInsnNode(value));\n      insn.add(new InsnNode(Opcodes.AASTORE));\n    }\n    return insn;\n  }\n\n  private InsnList loadEventFieldsDefs(List<AnnotationNode> fieldsDef) {\n    InsnList insn = new InsnList();\n    insn.add(new LdcInsnNode(fieldsDef.size()));\n    insn.add(new TypeInsnNode(Opcodes.ANEWARRAY, JFR_EVENT_TEMPLATE_FIELD_INTERNAL));\n    int cntr = 0;\n    for (AnnotationNode fieldDef : fieldsDef) {\n      insn.add(new InsnNode(Opcodes.DUP));\n      insn.add(new LdcInsnNode(cntr++));\n      insn.add(loadEventFieldDef(fieldDef));\n      insn.add(new InsnNode(Opcodes.AASTORE));\n    }\n    return insn;\n  }\n\n  private InsnList loadEventFieldDef(AnnotationNode fieldDef) {\n    InsnList insn = new InsnList();\n    Iterator<Object> iter = fieldDef.values.iterator();\n    String name = null;\n    String type = null;\n    String label = null;\n    String description = null;\n    String[] kind = null;\n    while (iter.hasNext()) {\n      String key = (String) iter.next();\n      switch (key) {\n        case \"name\":\n          {\n            name = (String) iter.next();\n            break;\n          }\n        case \"type\":\n          {\n            type = ((String[]) iter.next())[1];\n            break;\n          }\n        case \"label\":\n          {\n            label = (String) iter.next();\n            break;\n          }\n        case \"description\":\n          {\n            description = (String) iter.next();\n            break;\n          }\n        case \"kind\":\n          {\n            kind = getKind((AnnotationNode) iter.next());\n            break;\n          }\n      }\n    }\n    insn.add(new TypeInsnNode(Opcodes.NEW, JFR_EVENT_TEMPLATE_FIELD_INTERNAL));\n    insn.add(new InsnNode(Opcodes.DUP));\n    insn.add(new LdcInsnNode(name));\n    insn.add(new LdcInsnNode(type));\n    insn.add(\n        (label == null || label.isEmpty())\n            ? new InsnNode(Opcodes.ACONST_NULL)\n            : new LdcInsnNode(label));\n    insn.add(\n        (description == null || description.isEmpty())\n            ? new InsnNode(Opcodes.ACONST_NULL)\n            : new LdcInsnNode(description));\n    if (kind != null) {\n      if (!kind[0].equals(Event.FieldKind.NONE.name())) {\n        insn.add(new LdcInsnNode(kind[0]));\n        insn.add(\n            (kind[1] == null || kind[1].isEmpty())\n                ? new InsnNode(Opcodes.ACONST_NULL)\n                : new LdcInsnNode(kind[1]));\n      }\n    } else {\n      insn.add(new InsnNode(Opcodes.ACONST_NULL));\n      insn.add(new InsnNode(Opcodes.ACONST_NULL));\n    }\n    insn.add(\n        new MethodInsnNode(\n            Opcodes.INVOKESPECIAL,\n            JFR_EVENT_TEMPLATE_FIELD_INTERNAL,\n            \"<init>\",\n            \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V\",\n            false));\n    return insn;\n  }\n\n  private String[] getKind(AnnotationNode kindNode) {\n    Iterator<Object> iter = kindNode.values.iterator();\n    String name = null;\n    String value = null;\n    while (iter.hasNext()) {\n      String key = (String) iter.next();\n      switch (key) {\n        case \"name\":\n          {\n            name = ((String[]) iter.next())[1];\n            break;\n          }\n        case \"value\":\n          {\n            value = (String) iter.next();\n            break;\n          }\n      }\n    }\n    return new String[] {name, value};\n  }\n\n  private void addLevelField(ClassNode cn) {\n    if (cn.fields == null) {\n      cn.fields = new ArrayList<>();\n    }\n    cn.fields.add(\n        new FieldNode(\n            Opcodes.ASM9,\n            Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_VOLATILE,\n            Constants.BTRACE_LEVEL_FLD,\n            Constants.INT_DESC,\n            null,\n            0));\n  }\n\n  private void preprocessMethod(ClassNode cn, MethodNode mn) {\n    // !!! The order of execution is important here !!!\n    LocalVarGenerator lvg = new LocalVarGenerator(mn);\n    makePublic(mn);\n    checkAugmentedReturn(mn);\n    scanMethodInstructions(cn, mn, lvg);\n    addBTraceErrorHandler(cn, mn);\n    addBTraceRuntimeEnter(cn, mn);\n    addJfrHandlerField(cn, mn);\n\n    recalculateVars(mn);\n  }\n\n  private void makePublic(MethodNode mn) {\n    if (!mn.name.contains(\"init>\") && isUnannotated(mn)) {\n      if ((mn.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC) {\n        mn.access &= ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED);\n        mn.access |= Opcodes.ACC_PUBLIC;\n      }\n    }\n  }\n\n  private void processFields(ClassNode cn) {\n    Iterator<FieldNode> iter = getFields(cn).iterator();\n    while (iter.hasNext()) {\n      FieldNode fn = iter.next();\n      fn.access = (fn.access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) | Opcodes.ACC_PUBLIC;\n      tryProcessTLS(cn, fn);\n      tryProcessExport(cn, fn);\n      if (tryProcessInjected(fn) == null) {\n        iter.remove();\n      }\n      tryProcessEvent(fn);\n    }\n  }\n\n  private void tryProcessTLS(ClassNode cn, FieldNode fn) {\n    AnnotationNode an = null;\n    if ((an = getAnnotation(fn, TLS_TYPE)) != null) {\n      fn.visibleAnnotations.remove(an);\n      String origDesc = fn.desc;\n      String boxedDesc = boxDesc(origDesc);\n      fn.desc = Constants.THREAD_LOCAL_DESC;\n      fn.signature = fn.desc.substring(0, fn.desc.length() - 1) + \"<\" + boxedDesc + \">;\";\n      initTLS(cn, fn, origDesc);\n    }\n  }\n\n  private void tryProcessExport(ClassNode cn, FieldNode fn) {\n    AnnotationNode an = null;\n    if ((an = getAnnotation(fn, EXPORT_TYPE)) != null) {\n      fn.visibleAnnotations.remove(an);\n      String origDesc = fn.desc;\n\n      initExport(cn, fn, origDesc);\n    }\n  }\n\n  private FieldNode tryProcessInjected(FieldNode fn) {\n    AnnotationNode an = null;\n    if ((an = getAnnotation(fn, INJECTED_TYPE)) != null) {\n      if (fn.visibleAnnotations != null) fn.visibleAnnotations.remove(an);\n      if (fn.invisibleAnnotations != null) fn.invisibleAnnotations.remove(an);\n\n      injectedFlds.put(fn.name, an);\n      return null;\n    }\n    return fn;\n  }\n\n  private void tryProcessEvent(FieldNode fn) {\n    AnnotationNode an;\n    if ((an = getAnnotation(fn, EVENT_TYPE)) != null) {\n      if (fn.visibleAnnotations != null) fn.visibleAnnotations.remove(an);\n      if (fn.invisibleAnnotations != null) fn.invisibleAnnotations.remove(an);\n      eventFlds.put(fn.name, an);\n    }\n  }\n\n  private void initTLS(ClassNode cn, FieldNode fn, String typeDesc) {\n    tlsFldNames.add(fn.name);\n\n    initAnnotatedField(fn, typeDesc, tlsInitSequence(cn, fn.name, fn.desc));\n  }\n\n  private InsnList tlsInitSequence(ClassNode cn, String name, String desc) {\n    InsnList initList = new InsnList();\n    initList.add(\n        new MethodInsnNode(\n            Opcodes.INVOKESTATIC,\n            Constants.BTRACERTACCESS_INTERNAL,\n            \"newThreadLocal\",\n            NEW_TLS_DESC,\n            false));\n    initList.add(new FieldInsnNode(Opcodes.PUTSTATIC, cn.name, name, desc));\n    return initList;\n  }\n\n  private void initExport(ClassNode cn, FieldNode fn, String typeDesc) {\n    exportFldNames.add(fn.name);\n    initAnnotatedField(fn, typeDesc, exportInitSequence(cn, fn.name, fn.desc));\n  }\n\n  private InsnList exportInitSequence(ClassNode cn, String name, String desc) {\n    InsnList init = new InsnList();\n\n    init.add(getRuntimeImpl(cn));\n    init.add(new InsnNode(Opcodes.SWAP));\n    init.add(new LdcInsnNode(perfCounterName(cn, name)));\n    init.add(new LdcInsnNode(desc));\n    init.add(\n        new MethodInsnNode(\n            Opcodes.INVOKEINTERFACE,\n            Constants.BTRACERTBRIDGE_INTERNAL,\n            \"newPerfCounter\",\n            NEW_PERFCOUNTER_DESC,\n            true));\n\n    return init;\n  }\n\n  private void initAnnotatedField(FieldNode fn, String typeDesc, InsnList initList) {\n    Object initVal = fn.value;\n    fn.value = null;\n    fn.access |= Opcodes.ACC_FINAL;\n\n    InsnList l = clinit.instructions;\n\n    MethodInsnNode boxNode;\n    if (TypeUtils.isPrimitive(typeDesc)) {\n      boxNode = boxNode(typeDesc);\n      initList.insert(boxNode);\n    }\n\n    if (initVal != null) {\n      initList.insert(new LdcInsnNode(initVal));\n    } else {\n      // find first fld store; this is the initialization place\n      AbstractInsnNode initNode = findNodeInitialization(fn);\n\n      if (initNode != null) {\n        // found the initialization place;\n        // just replace the FLD_STORE with the field init sequence\n        l.insert(initNode, initList);\n        l.remove(initNode);\n        return;\n      } else {\n        // no initialization done; use primitive defaults or NULL\n        addDefaultVal(Type.getType(typeDesc), initList);\n      }\n    }\n    MethodInsnNode rtStart = findBTraceRuntimeStart();\n    if (rtStart != null) {\n      l.insertBefore(rtStart, initList);\n    } else {\n      l.add(initList);\n    }\n  }\n\n  private void addDefaultVal(Type t, InsnList l) {\n    switch (t.getSort()) {\n      case Type.INT:\n      case Type.SHORT:\n      case Type.BOOLEAN:\n      case Type.BYTE:\n      case Type.CHAR:\n        {\n          l.insert(new InsnNode(Opcodes.ICONST_0));\n          break;\n        }\n      case Type.LONG:\n        {\n          l.insert(new InsnNode(Opcodes.LCONST_0));\n          break;\n        }\n      case Type.FLOAT:\n        {\n          l.insert(new InsnNode(Opcodes.FCONST_0));\n          break;\n        }\n      case Type.DOUBLE:\n        {\n          l.insert(new InsnNode(Opcodes.DCONST_0));\n          break;\n        }\n      default:\n        {\n          l.insert(new InsnNode(Opcodes.ACONST_NULL));\n        }\n    }\n  }\n\n  @SuppressWarnings(\"unchecked\")\n  private void checkAugmentedReturn(MethodNode mn) {\n    if (isUnannotated(mn)) return;\n\n    Type retType = Type.getReturnType(mn.desc);\n    if (retType.getSort() != Type.VOID) {\n      if (getReturnMethodParameter(mn) == Integer.MIN_VALUE) {\n        // insert the method return parameter\n        String oldDesc = mn.desc;\n        Type[] args = Type.getArgumentTypes(mn.desc);\n        args = Arrays.copyOf(args, args.length + 1);\n        args[args.length - 1] = retType;\n\n        List<AnnotationNode> annots = new ArrayList<>();\n        AnnotationNode an = new AnnotationNode(Type.getDescriptor(Return.class));\n        annots.add(an);\n        mn.visibleParameterAnnotations =\n            mn.visibleParameterAnnotations != null\n                ? Arrays.copyOf(mn.visibleParameterAnnotations, args.length)\n                : new List[args.length];\n        mn.visibleParameterAnnotations[args.length - 1] = annots;\n        mn.desc = Type.getMethodDescriptor(retType, args);\n\n        if (mn instanceof BTraceMethodNode) {\n          BTraceMethodNode bmn = (BTraceMethodNode) mn;\n          OnMethod om = bmn.getOnMethod();\n\n          if (om != null\n              && om.getTargetName().equals(mn.name)\n              && om.getTargetDescriptor().equals(oldDesc)) {\n            om.setReturnParameter(getReturnMethodParameter(mn));\n            om.setTargetDescriptor(mn.desc);\n          }\n        }\n      }\n    }\n  }\n\n  private void scanMethodInstructions(ClassNode cn, MethodNode mn, LocalVarGenerator lvg) {\n    // ignore <init> and <clinit>\n    if (mn.name.startsWith(\"<\")) return;\n\n    serviceLocals.clear(); // initialize the service locals for this particular method\n\n    boolean checkFields =\n        !(tlsFldNames.isEmpty() && exportFldNames.isEmpty() && injectedFlds.isEmpty());\n\n    int retopcode = Type.getReturnType(mn.desc).getOpcode(Opcodes.IRETURN);\n    InsnList l = mn.instructions;\n    for (AbstractInsnNode n = l.getFirst(); n != null; n = n != null ? n.getNext() : null) {\n      int type = n.getType();\n      if (checkFields && type == AbstractInsnNode.FIELD_INSN) {\n        FieldInsnNode fin = (FieldInsnNode) n;\n        if (fin.owner.equals(cn.name)) {\n          if (tlsFldNames.contains(fin.name) && !fin.desc.equals(Constants.THREAD_LOCAL_DESC)) {\n            n = updateTLSUsage(fin, l);\n          } else if (exportFldNames.contains(fin.name)) {\n            n = updateExportUsage(cn, fin, l);\n          } else if (injectedFlds.containsKey(fin.name)) {\n            n = updateInjectedUsage(cn, fin, l, lvg);\n          }\n        }\n      } else if (n.getOpcode() == retopcode\n          && getClassifiers(mn).contains(MethodClassifier.RT_AWARE)) {\n        addBTraceRuntimeExit(cn, (InsnNode) n, l);\n      }\n    }\n  }\n\n  private void recalculateVars(MethodNode mn) {\n    for (AbstractInsnNode n = mn.instructions.getFirst(); n != null; n = n.getNext()) {\n      if (n.getType() == AbstractInsnNode.VAR_INSN) {\n        VarInsnNode vin = (VarInsnNode) n;\n        vin.var = LocalVarGenerator.translateIdx(vin.var);\n      }\n    }\n    StackTrackingMethodVisitor v =\n        new StackTrackingMethodVisitor(\n            new MethodVisitor(Opcodes.ASM9) {\n              @Override\n              public void visitMaxs(int maxStack, int maxLocals) {\n                super.visitMaxs(maxStack, maxLocals);\n                mn.maxStack = maxStack;\n                mn.maxLocals = maxLocals;\n              }\n            },\n            mn.name,\n            mn.desc,\n            (mn.access & Opcodes.ACC_STATIC) > 0);\n    mn.accept(v);\n  }\n\n  private void processClinit(ClassNode cn) {\n    for (MethodNode mn : getMethods(cn)) {\n      if (mn.name.equals(\"<clinit>\")) {\n        clinit = mn;\n        break;\n      }\n    }\n    if (clinit == null) {\n      clinit =\n          new MethodNode(\n              Opcodes.ASM9,\n              (Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC),\n              \"<clinit>\",\n              \"()V\",\n              null,\n              new String[0]);\n      clinit.instructions.add(new InsnNode(Opcodes.RETURN));\n      cn.methods.add(0, clinit);\n    }\n    initRuntime(cn, clinit);\n  }\n\n  private void initRuntime(ClassNode cn, MethodNode clinit) {\n    addRuntimeNode(cn);\n    InsnList l = new InsnList();\n\n    l.add(new LdcInsnNode(Type.getObjectType(cn.name)));\n    l.add(loadTimerHandlers(cn));\n    l.add(loadEventHandlers(cn));\n    l.add(loadErrorHandlers(cn));\n    l.add(loadExitHandlers(cn));\n    l.add(loadLowMemoryHandlers(cn));\n    l.add(\n        new MethodInsnNode(\n            Opcodes.INVOKESTATIC,\n            Constants.BTRACERTACCESS_INTERNAL,\n            \"forClass\",\n            BTRACERT_FOR_CLASS_DESC,\n            false));\n    l.add(new FieldInsnNode(Opcodes.PUTSTATIC, cn.name, rtField.name, rtField.desc));\n\n    // Mark where the error handler should start (after runtime is set)\n    clinitErrorHandlerStart = new LabelNode();\n    l.add(clinitErrorHandlerStart);\n\n    l.add(getRuntimeImpl(cn));\n    addRuntimeCheck(cn, clinit, l, true);\n\n    clinitEntryPoint = l.getLast();\n\n    clinit.instructions.insert(l);\n\n    startRuntime(cn, clinit);\n  }\n\n  private InsnList loadTimerHandlers(ClassNode cn) {\n    InsnList il = new InsnList();\n    int cnt = 0;\n    for (MethodNode mn : cn.methods) {\n      if (mn.visibleAnnotations != null) {\n        AnnotationNode an = mn.visibleAnnotations.get(0);\n        if (an.desc.equals(Constants.ONTIMER_DESC)) {\n          Iterator<?> anValueIterator = an.values != null ? an.values.iterator() : null;\n          if (anValueIterator != null) {\n            long period = -1;\n            String property = null;\n\n            while (anValueIterator.hasNext()) {\n              String key = (String) anValueIterator.next();\n              Object value = anValueIterator.next();\n\n              if (value != null) {\n                switch (key) {\n                  case \"value\":\n                    {\n                      period = (Long) value;\n                      break;\n                    }\n                  case \"from\":\n                    {\n                      property = (String) value;\n                      break;\n                    }\n                }\n              }\n            }\n            il.add(new InsnNode(Opcodes.DUP));\n            il.add(new LdcInsnNode(cnt++));\n            il.add(new TypeInsnNode(Opcodes.NEW, TIMERHANDLER_INTERNAL));\n            il.add(new InsnNode(Opcodes.DUP));\n            il.add(new LdcInsnNode(mn.name));\n            il.add(new LdcInsnNode(period));\n            il.add(\n                property != null ? new LdcInsnNode(property) : new InsnNode(Opcodes.ACONST_NULL));\n            il.add(\n                new MethodInsnNode(\n                    Opcodes.INVOKESPECIAL,\n                    TIMERHANDLER_INTERNAL,\n                    \"<init>\",\n                    \"(Ljava/lang/String;JLjava/lang/String;)V\",\n                    false));\n            il.add(new InsnNode(Opcodes.AASTORE));\n          }\n        }\n      }\n    }\n    if (cnt > 0) {\n      InsnList newArray = new InsnList();\n      newArray.add(new LdcInsnNode(cnt));\n      newArray.add(new TypeInsnNode(Opcodes.ANEWARRAY, TIMERHANDLER_INTERNAL));\n      il.insert(newArray);\n    } else {\n      il.insert(new InsnNode(Opcodes.ACONST_NULL));\n    }\n\n    return il;\n  }\n\n  private InsnList loadEventHandlers(ClassNode cn) {\n    InsnList il = new InsnList();\n    int cnt = 0;\n    for (MethodNode mn : cn.methods) {\n      if (mn.visibleAnnotations != null) {\n        AnnotationNode an = mn.visibleAnnotations.get(0);\n        if (an.desc.equals(Constants.ONEVENT_DESC)) {\n          il.add(new InsnNode(Opcodes.DUP));\n          il.add(new LdcInsnNode(cnt++));\n          il.add(new TypeInsnNode(Opcodes.NEW, EVENTHANDLER_INTERNAL));\n          il.add(new InsnNode(Opcodes.DUP));\n          il.add(new LdcInsnNode(mn.name));\n          il.add(\n              an.values != null\n                  ? new LdcInsnNode(an.values.get(1))\n                  : new InsnNode(Opcodes.ACONST_NULL));\n          il.add(\n              new MethodInsnNode(\n                  Opcodes.INVOKESPECIAL,\n                  EVENTHANDLER_INTERNAL,\n                  \"<init>\",\n                  \"(Ljava/lang/String;Ljava/lang/String;)V\",\n                  false));\n          il.add(new InsnNode(Opcodes.AASTORE));\n        }\n      }\n    }\n    if (cnt > 0) {\n      InsnList newArray = new InsnList();\n      newArray.add(new LdcInsnNode(cnt));\n      newArray.add(new TypeInsnNode(Opcodes.ANEWARRAY, EVENTHANDLER_INTERNAL));\n      il.insert(newArray);\n    } else {\n      il.insert(new InsnNode(Opcodes.ACONST_NULL));\n    }\n\n    return il;\n  }\n\n  private InsnList loadErrorHandlers(ClassNode cn) {\n    InsnList il = new InsnList();\n    int cnt = 0;\n    for (MethodNode mn : cn.methods) {\n      if (mn.visibleAnnotations != null) {\n        AnnotationNode an = mn.visibleAnnotations.get(0);\n        if (an.desc.equals(Constants.ONERROR_DESC)) {\n          il.add(new InsnNode(Opcodes.DUP));\n          il.add(new LdcInsnNode(cnt++));\n          il.add(new TypeInsnNode(Opcodes.NEW, ERRORHANDLER_INTERNAL));\n          il.add(new InsnNode(Opcodes.DUP));\n          il.add(new LdcInsnNode(mn.name));\n          il.add(\n              new MethodInsnNode(\n                  Opcodes.INVOKESPECIAL,\n                  ERRORHANDLER_INTERNAL,\n                  \"<init>\",\n                  \"(Ljava/lang/String;)V\",\n                  false));\n          il.add(new InsnNode(Opcodes.AASTORE));\n        }\n      }\n    }\n    if (cnt > 0) {\n      InsnList newArray = new InsnList();\n      newArray.add(new LdcInsnNode(cnt));\n      newArray.add(new TypeInsnNode(Opcodes.ANEWARRAY, ERRORHANDLER_INTERNAL));\n      il.insert(newArray);\n    } else {\n      il.insert(new InsnNode(Opcodes.ACONST_NULL));\n    }\n\n    return il;\n  }\n\n  private InsnList loadExitHandlers(ClassNode cn) {\n    InsnList il = new InsnList();\n    int cnt = 0;\n    for (MethodNode mn : cn.methods) {\n      if (mn.visibleAnnotations != null) {\n        AnnotationNode an = mn.visibleAnnotations.get(0);\n        if (an.desc.equals(Constants.ONEXIT_DESC)) {\n          il.add(new InsnNode(Opcodes.DUP));\n          il.add(new LdcInsnNode(cnt++));\n          il.add(new TypeInsnNode(Opcodes.NEW, EXITHANDLER_INTERNAL));\n          il.add(new InsnNode(Opcodes.DUP));\n          il.add(new LdcInsnNode(mn.name));\n          il.add(\n              new MethodInsnNode(\n                  Opcodes.INVOKESPECIAL,\n                  EXITHANDLER_INTERNAL,\n                  \"<init>\",\n                  \"(Ljava/lang/String;)V\",\n                  false));\n          il.add(new InsnNode(Opcodes.AASTORE));\n        }\n      }\n    }\n    if (cnt > 0) {\n      InsnList newArray = new InsnList();\n      newArray.add(new LdcInsnNode(cnt));\n      newArray.add(new TypeInsnNode(Opcodes.ANEWARRAY, EXITHANDLER_INTERNAL));\n      il.insert(newArray);\n    } else {\n      il.insert(new InsnNode(Opcodes.ACONST_NULL));\n    }\n\n    return il;\n  }\n\n  private InsnList loadLowMemoryHandlers(ClassNode cn) {\n    InsnList il = new InsnList();\n    int cnt = 0;\n    for (MethodNode mn : cn.methods) {\n      if (mn.visibleAnnotations != null) {\n        AnnotationNode an = mn.visibleAnnotations.get(0);\n        if (an.desc.equals(Constants.ONLOWMEMORY_DESC)) {\n          String pool = \"\";\n          long threshold = Long.MAX_VALUE;\n          String thresholdProp = null;\n\n          for (int i = 0; i < an.values.size(); i += 2) {\n            String key = (String) an.values.get(i);\n            Object val = an.values.get(i + 1);\n            switch (key) {\n              case \"pool\":\n                {\n                  pool = (String) val;\n                  break;\n                }\n              case \"threshold\":\n                {\n                  threshold = (long) val;\n                  break;\n                }\n              case \"thresholdFrom\":\n                {\n                  thresholdProp = (String) val;\n                  break;\n                }\n            }\n          }\n          il.add(new InsnNode(Opcodes.DUP));\n          il.add(new LdcInsnNode(cnt++));\n          il.add(new TypeInsnNode(Opcodes.NEW, LOWMEMORYHANDLER_INTERNAL));\n          il.add(new InsnNode(Opcodes.DUP));\n          il.add(new LdcInsnNode(mn.name));\n          il.add(new LdcInsnNode(pool));\n          il.add(new LdcInsnNode(threshold));\n          il.add(new LdcInsnNode(thresholdProp));\n          il.add(\n              new MethodInsnNode(\n                  Opcodes.INVOKESPECIAL,\n                  LOWMEMORYHANDLER_INTERNAL,\n                  \"<init>\",\n                  \"(Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;)V\",\n                  false));\n          il.add(new InsnNode(Opcodes.AASTORE));\n        }\n      }\n    }\n    if (cnt > 0) {\n      InsnList newArray = new InsnList();\n      newArray.add(new LdcInsnNode(cnt));\n      newArray.add(new TypeInsnNode(Opcodes.ANEWARRAY, EXITHANDLER_INTERNAL));\n      il.insert(newArray);\n    } else {\n      il.insert(new InsnNode(Opcodes.ACONST_NULL));\n    }\n\n    return il;\n  }\n\n  private void startRuntime(ClassNode cNode, MethodNode clinit1) {\n    for (AbstractInsnNode n = clinit1.instructions.getFirst(); n != null; n = n.getNext()) {\n      if (n.getOpcode() == Opcodes.RETURN) {\n        AbstractInsnNode prev = n.getPrevious();\n        if (prev != null && prev.getType() == AbstractInsnNode.METHOD_INSN) {\n          MethodInsnNode minNode = (MethodInsnNode) prev;\n          if (minNode.name.equals(\"leave\")) {\n            // don't start the runtime if we are bailing out (BTraceRuntime.leave())\n            continue;\n          }\n        }\n        InsnList il = new InsnList();\n        il.add(getRuntimeImpl(cNode));\n        il.add(\n            new MethodInsnNode(\n                Opcodes.INVOKEINTERFACE, Constants.BTRACERTBRIDGE_INTERNAL, \"start\", \"()V\", true));\n        clinit1.instructions.insertBefore(n, il);\n      }\n    }\n  }\n\n  private FieldInsnNode getRuntimeImpl(ClassNode cn) {\n    return new FieldInsnNode(Opcodes.GETSTATIC, cn.name, rtField.name, rtField.desc);\n  }\n\n  private InsnList getRuntimeExit(ClassNode cn) {\n    InsnList il = new InsnList();\n    il.add(getRuntimeImpl(cn));\n    il.add(\n        new MethodInsnNode(\n            Opcodes.INVOKEINTERFACE, Constants.BTRACERTBRIDGE_INTERNAL, \"leave\", \"()V\", true));\n    return il;\n  }\n\n  private void addRuntimeNode(ClassNode cn) {\n    rtField =\n        new FieldNode(\n            Opcodes.ASM9,\n            (Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC),\n            \"runtime\",\n            Type.getDescriptor(BTraceRuntimeBridge.class),\n            null,\n            null);\n    cn.fields.add(0, rtField);\n  }\n\n  private void addBTraceErrorHandler(ClassNode cn, MethodNode mn) {\n    if (!mn.name.equals(\"<clinit>\") && isUnannotated(mn)) return;\n\n    EnumSet<MethodClassifier> clsf = getClassifiers(mn);\n    if (!clsf.isEmpty()) {\n      LabelNode from;\n      LabelNode to = new LabelNode();\n      InsnList l = mn.instructions;\n\n      // For <clinit>, start the error handler AFTER the runtime is set\n      // to avoid NPE when handling exceptions thrown during runtime setup\n      if (mn.name.equals(\"<clinit>\") && clinitErrorHandlerStart != null) {\n        from = clinitErrorHandlerStart;\n      } else {\n        from = new LabelNode();\n        l.insert(from);\n      }\n      l.add(to);\n      // add proper stackframe map node\n      l.add(throwableHandlerFrame(mn));\n\n      l.add(getRuntimeImpl(cn));\n      l.add(new InsnNode(Opcodes.DUP_X1));\n      l.add(new InsnNode(Opcodes.SWAP));\n      l.add(\n          new MethodInsnNode(\n              Opcodes.INVOKEINTERFACE,\n              Constants.BTRACERTBRIDGE_INTERNAL,\n              \"handleException\",\n              BTRACERT_HANDLE_EXCEPTION_DESC,\n              true));\n      l.add(getReturnSequence(cn, mn, true));\n\n      mn.tryCatchBlocks.add(new TryCatchBlockNode(from, to, to, Constants.THROWABLE_INTERNAL));\n    }\n  }\n\n  private FrameNode throwableHandlerFrame(MethodNode mn) {\n    List<Object> locals = new ArrayList<>();\n    for (Type argType : Type.getArgumentTypes(mn.desc)) {\n      if (TypeUtils.isPrimitive(argType)) {\n        switch (argType.getSort()) {\n          case Type.INT:\n          case Type.BOOLEAN:\n          case Type.BYTE:\n          case Type.CHAR:\n            {\n              locals.add(Opcodes.INTEGER);\n              break;\n            }\n          case Type.FLOAT:\n            {\n              locals.add(Opcodes.FLOAT);\n              break;\n            }\n          case Type.DOUBLE:\n            {\n              locals.add(Opcodes.DOUBLE);\n              break;\n            }\n          case Type.LONG:\n            {\n              locals.add(Opcodes.LONG);\n              break;\n            }\n        }\n      } else {\n        locals.add(argType.getInternalName());\n      }\n    }\n    return new FrameNode(\n        Opcodes.F_FULL,\n        locals.size(),\n        locals.toArray(new Object[0]),\n        1,\n        new Object[] {Constants.THROWABLE_INTERNAL});\n  }\n\n  private void addBTraceRuntimeEnter(ClassNode cn, MethodNode mn) {\n    // no runtime check for <clinit>\n    if (mn.name.equals(\"<clinit>\")) return;\n\n    EnumSet<MethodClassifier> clsf = getClassifiers(mn);\n    if (clsf.contains(MethodClassifier.RT_AWARE)) {\n      InsnList entryCheck = new InsnList();\n      entryCheck.add(getRuntimeImpl(cn));\n      if (clsf.contains(MethodClassifier.GUARDED)) {\n        addRuntimeCheck(cn, mn, entryCheck, false);\n      }\n      mn.instructions.insert(entryCheck);\n    }\n  }\n\n  private void addRuntimeCheck(ClassNode cn, MethodNode mn, InsnList entryCheck, boolean b) {\n    LabelNode start = new LabelNode();\n    entryCheck.add(\n        new MethodInsnNode(\n            Opcodes.INVOKESTATIC,\n            Constants.BTRACERTACCESS_INTERNAL,\n            \"enter\",\n            BTRACERT_ENTER_DESC,\n            false));\n    entryCheck.add(new JumpInsnNode(Opcodes.IFNE, start));\n    entryCheck.add(getReturnSequence(cn, mn, b));\n    entryCheck.add(start);\n    entryCheck.add(new FrameNode(Opcodes.F_SAME, 0, null, 0, null));\n  }\n\n  private void addBTraceRuntimeExit(ClassNode cn, InsnNode n, InsnList l) {\n    l.insertBefore(n, getRuntimeExit(cn));\n  }\n\n  private void addJfrHandlerField(ClassNode cn, MethodNode mn) {\n    if (mn.visibleAnnotations != null) {\n      for (AnnotationNode annotation : mn.visibleAnnotations) {\n        if (annotation.desc.equals(Constants.JFRPERIODIC_DESC)) {\n          String fldName = JFR_HANDLER_FIELD_PREFIX + mn.name;\n          cn.fields.add(\n              new FieldNode(\n                  Opcodes.ASM9,\n                  Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,\n                  fldName,\n                  Constants.JFREVENTFACTORY_DESC,\n                  null,\n                  null));\n          eventFlds.put(fldName, annotation);\n        }\n      }\n    }\n  }\n\n  private List<MethodNode> getMethods(ClassNode cn) {\n    return cn.methods;\n  }\n\n  private List<FieldNode> getFields(ClassNode cn) {\n    return cn.fields;\n  }\n\n  private List<AnnotationNode> getAnnotations(MethodNode mn) {\n    return mn.visibleAnnotations != null ? mn.visibleAnnotations : Collections.emptyList();\n  }\n\n  private EnumSet<MethodClassifier> getClassifiers(MethodNode mn) {\n    // thread safe; check-modification will be done in single thread only for each instance of\n    // Preprocessor\n    EnumSet<MethodClassifier> classifiers = classifierMap.get(mn);\n    if (classifiers != null) {\n      return classifiers;\n    }\n    // <clinit> will always be guarded by BTrace error handler\n    if (mn.name.equals(\"<clinit>\")) {\n      classifiers = EnumSet.of(MethodClassifier.RT_AWARE);\n      classifierMap.put(mn, classifiers);\n      return classifiers;\n    }\n\n    // JFR event handlers will alwyas be guarded by BTrace error handler\n    if (jfrHandlerNames.contains(mn.name)) {\n      classifiers = EnumSet.of(MethodClassifier.RT_AWARE, MethodClassifier.GUARDED);\n      classifierMap.put(mn, classifiers);\n      return classifiers;\n    }\n\n    List<AnnotationNode> annots = getAnnotations(mn);\n    classifiers = EnumSet.noneOf(MethodClassifier.class);\n    if (!annots.isEmpty()) {\n      for (AnnotationNode an : annots) {\n        if (RT_AWARE_ANNOTS.contains(an.desc)) {\n          classifiers.add(MethodClassifier.RT_AWARE);\n        }\n        if (GUARDED_ANNOTS.contains(an.desc)) {\n          classifiers.add(MethodClassifier.GUARDED);\n        }\n      }\n    }\n    classifierMap.put(mn, classifiers);\n    return classifiers;\n  }\n\n  private FieldInsnNode findNodeInitialization(FieldNode fn) {\n    for (AbstractInsnNode n = clinit.instructions.getFirst(); n != null; n = n.getNext()) {\n      if (n.getType() == AbstractInsnNode.FIELD_INSN) {\n        FieldInsnNode fldInsnNode = (FieldInsnNode) n;\n        if (fldInsnNode.getOpcode() == Opcodes.PUTSTATIC && fldInsnNode.name.equals(fn.name)) {\n          return fldInsnNode;\n        }\n      }\n    }\n    return null;\n  }\n\n  private MethodInsnNode findBTraceRuntimeStart() {\n    for (AbstractInsnNode n = clinit.instructions.getFirst(); n != null; n = n.getNext()) {\n      if (n.getType() == AbstractInsnNode.METHOD_INSN) {\n        MethodInsnNode minNode = (MethodInsnNode) n;\n        if (minNode.getOpcode() == Opcodes.INVOKEINTERFACE\n            && minNode.owner.equals(Constants.BTRACERTBRIDGE_INTERNAL)\n            && minNode.name.equals(\"start\")) {\n          return minNode;\n        }\n      }\n    }\n    return null;\n  }\n\n  private AbstractInsnNode updateTLSUsage(FieldInsnNode fin, InsnList l) {\n    String unboxedDesc = fin.desc;\n    int opcode = fin.getOpcode();\n    // retrieve the TLS field\n    fin.setOpcode(Opcodes.GETSTATIC);\n    // change the desc from the contained type to TLS type\n    fin.desc = Constants.THREAD_LOCAL_DESC;\n\n    String boxedDesc = boxDesc(unboxedDesc);\n\n    if (opcode == Opcodes.GETSTATIC) {\n      InsnList toInsert = new InsnList();\n      MethodInsnNode getNode =\n          new MethodInsnNode(\n              Opcodes.INVOKEVIRTUAL, Constants.THREAD_LOCAL_INTERNAL, \"get\", TLS_GET_DESC, false);\n      toInsert.add(getNode);\n      String boxedInternal = boxedDesc.substring(1, boxedDesc.length() - 1);\n      toInsert.add(new TypeInsnNode(Opcodes.CHECKCAST, boxedInternal));\n      if (!boxedDesc.equals(unboxedDesc)) {\n        // must unbox\n        MethodInsnNode unboxNode = unboxNode(boxedDesc, boxedInternal, unboxedDesc);\n        if (unboxNode != null) {\n          toInsert.add(unboxNode);\n        }\n      }\n      l.insert(fin, toInsert);\n    } else if (opcode == Opcodes.PUTSTATIC) {\n      MethodInsnNode boxNode = null;\n      if (!boxedDesc.equals(unboxedDesc)) {\n        // must box\n        boxNode = boxNode(unboxedDesc, boxedDesc);\n        l.insert(fin.getPrevious(), boxNode);\n      }\n      MethodInsnNode setNode =\n          new MethodInsnNode(\n              Opcodes.INVOKEVIRTUAL, Constants.THREAD_LOCAL_INTERNAL, \"set\", TLS_SET_DESC, false);\n      l.insert(fin, setNode);\n      /* The stack is\n         -> ThreadLocal instance\n         -> value\n         ...\n\n         and we need\n         -> value\n         -> ThreadLocal instance\n         ...\n\n        Therefore we need to swap the topmost 2 elements\n      */\n      l.insertBefore(setNode, new InsnNode(Opcodes.SWAP));\n    }\n    return fin;\n  }\n\n  private AbstractInsnNode updateExportUsage(ClassNode cn, FieldInsnNode fin, InsnList l) {\n    String prefix = null;\n    boolean isPut = false;\n    // all the perf related methods start either with 'getPerf' or 'putPerf'\n    // the second part of the method name is extracted from the field type\n    if (fin.getOpcode() == Opcodes.GETSTATIC) {\n      prefix = \"getPerf\";\n    } else {\n      isPut = true;\n      prefix = \"putPerf\";\n    }\n    String methodName = null;\n    Type tType = null;\n\n    Type t = Type.getType(fin.desc);\n    switch (t.getSort()) {\n      case Type.INT:\n      case Type.SHORT:\n      case Type.BYTE:\n      case Type.CHAR:\n      case Type.BOOLEAN:\n        {\n          methodName = prefix + \"Int\";\n          tType = Type.INT_TYPE;\n          break;\n        }\n      case Type.LONG:\n        {\n          methodName = prefix + \"Long\";\n          tType = Type.LONG_TYPE;\n          break;\n        }\n      case Type.FLOAT:\n        {\n          methodName = prefix + \"Float\";\n          tType = Type.FLOAT_TYPE;\n          break;\n        }\n      case Type.DOUBLE:\n        {\n          methodName = prefix + \"Double\";\n          tType = Type.DOUBLE_TYPE;\n          break;\n        }\n      case Type.OBJECT:\n        {\n          if (t.equals(Constants.STRING_TYPE)) {\n            methodName = prefix + \"String\";\n            tType = Constants.STRING_TYPE;\n          }\n          break;\n        }\n    }\n    if (methodName == null) {\n      // if the perf counter is not accessible\n      // just put null on the stack for GETSTATIC\n      // and remove the topmost item from the stack for PUTSTATIC\n      l.insert(fin, isPut ? new InsnNode(Opcodes.POP) : new InsnNode(Opcodes.ACONST_NULL));\n    } else {\n      InsnList toInsert = new InsnList();\n      toInsert.add(getRuntimeImpl(cn));\n      if (isPut) {\n        // if the 'value' is on stack swap it with the rt instance to have the stack in required\n        // order\n        if (tType.getSize() == 1) {\n          toInsert.add(new InsnNode(Opcodes.SWAP));\n        } else {\n          toInsert.add(new InsnNode(Opcodes.DUP_X2));\n          toInsert.add(new InsnNode(Opcodes.POP));\n        }\n      }\n      toInsert.add(new LdcInsnNode(perfCounterName(cn, fin.name)));\n      toInsert.add(\n          new MethodInsnNode(\n              Opcodes.INVOKEINTERFACE,\n              Constants.BTRACERTBRIDGE_INTERNAL,\n              methodName,\n              isPut\n                  ? Type.getMethodDescriptor(Type.VOID_TYPE, tType, Constants.STRING_TYPE)\n                  : Type.getMethodDescriptor(tType, Constants.STRING_TYPE),\n              true));\n      l.insert(fin, toInsert);\n    }\n    AbstractInsnNode ret = fin.getNext();\n    l.remove(fin);\n    return ret;\n  }\n\n  /**\n   * Ensures that the extension providing the given service class is loaded.\n   * Uses reflection to access Main.getExtensionLoader() to avoid compile-time\n   * dependency on btrace-agent module.\n   *\n   * @param serviceClassName fully qualified service class name\n   */\n  private void ensureExtensionLoaded(String serviceClassName) {\n    try {\n      // Use reflection to obtain the agent's ExtensionLoader instance\n      Class<?> mainClass = Class.forName(\"org.openjdk.btrace.agent.Main\");\n      Method getLoaderMethod = mainClass.getMethod(\"getExtensionLoader\");\n      Object extensionLoader = getLoaderMethod.invoke(null);\n\n      if (extensionLoader == null) {\n        return; // Extension system not initialized; let later resolution fail clearly\n      }\n\n      // Find an extension that provides this service API\n      Class<?> loaderClass = extensionLoader.getClass();\n      Method findMethod = loaderClass.getMethod(\"findExtensionForService\", String.class);\n      Object descriptor = findMethod.invoke(extensionLoader, serviceClassName);\n\n      if (descriptor != null) {\n        // Ensure API JAR is appended to bootstrap, then load implementation if needed\n        try {\n          Method ensureApi = loaderClass.getMethod(\"ensureApiOnBootstrap\", descriptor.getClass());\n          ensureApi.invoke(extensionLoader, descriptor);\n        } catch (NoSuchMethodException ignored) {\n          // Older loaders may not expose this method; continue to load()\n        }\n\n        // Invoke a compatible load(...) method\n        try {\n          Method loadMethod = loaderClass.getMethod(\"load\", descriptor.getClass());\n          loadMethod.invoke(extensionLoader, descriptor);\n        } catch (NoSuchMethodException nsme) {\n          for (Method m : loaderClass.getMethods()) {\n            if (m.getName().equals(\"load\")\n                && m.getParameterCount() == 1\n                && m.getParameterTypes()[0].isAssignableFrom(descriptor.getClass())) {\n              m.invoke(extensionLoader, descriptor);\n              break;\n            }\n          }\n        }\n      }\n    } catch (Exception ignored) {\n      // Best-effort only; if extension/system not ready, resolution can fail later with details\n    }\n  }\n\n  private AbstractInsnNode updateInjectedUsage(\n      ClassNode cn, FieldInsnNode fin, InsnList l, LocalVarGenerator lvg) {\n    if (serviceLocals.containsKey(fin.name)) {\n      VarInsnNode load =\n          new VarInsnNode(\n              Type.getType(fin.desc).getOpcode(Opcodes.ILOAD), serviceLocals.get(fin.name));\n      l.insert(fin, load);\n      l.remove(fin);\n      return load;\n    }\n\n    InsnList toInsert = new InsnList();\n    AnnotationNode an = injectedFlds.get(fin.name);\n    Type serviceType = Type.getType(fin.desc);\n\n    // Ensure extension providing this service is loaded\n    ensureExtensionLoaded(serviceType.getClassName());\n\n    String svcType = \"SIMPLE\";\n    String fctryMethod = null;\n    int optionalFlag = 0;\n    String injectMode = \"UNSPECIFIED\";\n    if (an.values != null) {\n      Iterator<Object> iter = an.values.iterator();\n      while (iter.hasNext()) {\n        String name = (String) iter.next();\n        Object val = iter.next();\n        switch (name) {\n          case \"value\":\n            svcType = ((String[]) val)[1];\n            break;\n          case \"factoryMethod\":\n            fctryMethod = (String) val;\n            break;\n          case \"optional\":\n            if (val instanceof Boolean) {\n              optionalFlag = ((Boolean) val) ? 1 : 0;\n            }\n            break;\n          case \"mode\":\n            // enum value represented as String[]: [ \"Lpkg/Enum;\", \"NAME\" ]\n            if (val instanceof String[]) {\n              injectMode = ((String[]) val)[1];\n            }\n            break;\n        }\n      }\n    }\n    // Auto-detect extension types based on class hierarchy\n    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();\n    if (svcType.equals(\"SIMPLE\") && isExtensionType(serviceType, contextClassLoader)) {\n      svcType = \"EXTENSION\";\n    }\n    int varIdx = lvg.newVar(serviceType);\n    // Always use invokedynamic bridge to obtain the service instance\n    MethodType mt =\n        MethodType.methodType(\n            CallSite.class,\n            MethodHandles.Lookup.class,\n            String.class,\n            MethodType.class,\n            String.class,\n            String.class,\n            String.class,\n            Integer.class,\n            String.class);\n    Handle bsm =\n        new Handle(\n            Opcodes.H_INVOKESTATIC,\n            \"org/openjdk/btrace/runtime/ExtensionIndy\",\n            \"bootstrapFieldGet\",\n            mt.toMethodDescriptorString(),\n            false);\n\n    String factory = (fctryMethod != null) ? fctryMethod : \"\";\n    InvokeDynamicInsnNode indy =\n        new InvokeDynamicInsnNode(\n            fin.name,\n            Type.getMethodDescriptor(serviceType),\n            bsm,\n            serviceType.getClassName(),\n            svcType,\n            factory,\n            optionalFlag,\n            injectMode);\n\n    toInsert.add(indy);\n    toInsert.add(new InsnNode(Opcodes.DUP));\n    toInsert.add(new VarInsnNode(Opcodes.ASTORE, varIdx));\n    l.insert(fin, toInsert);\n    AbstractInsnNode next = fin.getNext();\n    l.remove(fin);\n    serviceLocals.put(fin.name, varIdx);\n    return next;\n  }\n\n  \n\n  private InsnList getReturnSequence(ClassNode cn, MethodNode mn, boolean addRuntimeExit) {\n    InsnList l = new InsnList();\n    Type retType = Type.getReturnType(mn.desc);\n    if (!retType.equals(Type.VOID_TYPE)) {\n      int retIndex = -1;\n      if (mn.visibleParameterAnnotations != null) {\n        int offset = 0;\n        Type[] params = Type.getArgumentTypes(mn.desc);\n        for (int i = 0; i < mn.visibleParameterAnnotations.length; i++) {\n          if (mn.visibleParameterAnnotations[i] != null) {\n            for (AnnotationNode an : mn.visibleParameterAnnotations[i]) {\n              if (an.desc.equals(Type.getDescriptor(Return.class))) {\n                retIndex = offset;\n              }\n            }\n          }\n          offset += params[i].getSize();\n        }\n      }\n      if (retIndex > -1) {\n        l.add(new VarInsnNode(retType.getOpcode(Opcodes.ILOAD), retIndex));\n      } else {\n        switch (retType.getSort()) {\n          case Type.INT:\n          case Type.SHORT:\n          case Type.BYTE:\n          case Type.CHAR:\n          case Type.BOOLEAN:\n            {\n              l.add(new InsnNode(Opcodes.ICONST_0));\n              break;\n            }\n          case Type.LONG:\n            {\n              l.add(new InsnNode(Opcodes.LCONST_0));\n              break;\n            }\n          case Type.FLOAT:\n            {\n              l.add(new InsnNode(Opcodes.FCONST_0));\n              break;\n            }\n          case Type.DOUBLE:\n            {\n              l.add(new InsnNode(Opcodes.DCONST_0));\n              break;\n            }\n          case Type.ARRAY:\n          case Type.OBJECT:\n            {\n              l.add(new InsnNode(Opcodes.ACONST_NULL));\n              break;\n            }\n        }\n      }\n    }\n    if (addRuntimeExit) {\n      l.add(getRuntimeExit(cn));\n    }\n    l.add(new InsnNode(retType.getOpcode(Opcodes.IRETURN)));\n    return l;\n  }\n\n  private String perfCounterName(ClassNode cn, String fieldName) {\n    return BTRACE_COUNTER_PREFIX + Type.getObjectType(cn.name).getInternalName() + \".\" + fieldName;\n  }\n\n  private String boxDesc(String desc) {\n    String boxed_desc = BOX_TYPE_MAP.get(desc);\n    return boxed_desc != null ? boxed_desc : desc;\n  }\n\n  private MethodInsnNode boxNode(String unboxedDesc) {\n    String boxedDesc = boxDesc(unboxedDesc);\n    if (boxedDesc != null) {\n      return boxNode(unboxedDesc, boxedDesc);\n    }\n    return null;\n  }\n\n  private MethodInsnNode boxNode(String unboxedDesc, String boxedDesc) {\n    return new MethodInsnNode(\n        Opcodes.INVOKESTATIC,\n        boxedDesc.substring(1, boxedDesc.length() - 1),\n        \"valueOf\",\n        \"(\" + unboxedDesc + \")\" + boxedDesc,\n        false);\n  }\n\n  /**\n   * Add the instruction sequence to print the message using {@linkplain DebugSupport}\n   *\n   * @param msg message\n   * @return the instruction list\n   */\n  private InsnList debugPrint(String msg) {\n    InsnList list = new InsnList();\n    list.add(msg != null ? new LdcInsnNode(msg) : new InsnNode(Opcodes.ACONST_NULL));\n    list.add(\n        new MethodInsnNode(\n            Opcodes.INVOKESTATIC,\n            \"org/openjdk/btrace/core/DebugSupport\",\n            \"info\",\n            \"(Ljava/lang/String;)V\"));\n    return list;\n  }\n\n  private MethodInsnNode unboxNode(String boxedDesc, String boxedInternal, String unboxedDesc) {\n    String mName = null;\n    switch (boxedDesc) {\n      case Constants.INTEGER_BOXED_DESC:\n        {\n          mName = \"intValue\";\n          break;\n        }\n      case Constants.SHORT_BOXED_DESC:\n        {\n          mName = \"shortValue\";\n          break;\n        }\n      case Constants.LONG_BOXED_DESC:\n        {\n          mName = \"longValue\";\n          break;\n        }\n      case Constants.FLOAT_BOXED_DESC:\n        {\n          mName = \"floatValue\";\n          break;\n        }\n      case Constants.DOUBLE_BOXED_DESC:\n        {\n          mName = \"doubleValue\";\n          break;\n        }\n      case Constants.BOOLEAN_BOXED_DESC:\n        {\n          mName = \"booleanValue\";\n          break;\n        }\n      case Constants.CHARACTER_BOXED_DESC:\n        {\n          mName = \"charValue\";\n          break;\n        }\n    }\n\n    if (mName != null) {\n      return new MethodInsnNode(\n          Opcodes.INVOKEVIRTUAL, boxedInternal, mName, \"()\" + unboxedDesc, false);\n    }\n    return null;\n  }\n\n  private int getReturnMethodParameter(MethodNode mn) {\n    if (mn.visibleParameterAnnotations != null) {\n      for (int i = 0; i < mn.visibleParameterAnnotations.length; i++) {\n        List paList = mn.visibleParameterAnnotations[i];\n        if (paList != null) {\n          for (Object anObj : paList) {\n            AnnotationNode an = (AnnotationNode) anObj;\n            if (an.desc.equals(Constants.RETURN_DESC)) {\n              return i;\n            }\n          }\n        }\n      }\n    }\n    return Integer.MIN_VALUE;\n  }\n\n  private enum MethodClassifier {\n    /**\n     * An annotated method that will need access to the current {@linkplain BTraceRuntime} instance.\n     */\n    RT_AWARE,\n    /**\n     * An annotated method that will use the result of {@linkplain BTraceRuntime#enter()} to skip\n     * the execution if already inside a handler. This implies the method is also {@linkplain\n     * MethodClassifier#RT_AWARE}.\n     */\n    GUARDED\n  }\n\n  private static class LocalVarGenerator {\n    private int offset = 0;\n\n    LocalVarGenerator(MethodNode mn) {\n      Type[] args = Type.getArgumentTypes(mn.desc);\n      for (Type t : args) {\n        offset += t.getSize();\n      }\n      if (mn.maxLocals > offset) {\n        offset = mn.maxLocals;\n      }\n    }\n\n    static int translateIdx(int idx) {\n      if (idx < 0) {\n        return -idx - 1;\n      }\n      return idx;\n    }\n\n    int newVar(Type t) {\n      int ret = -offset - 1;\n      offset += t.getSize();\n      return ret;\n    }\n\n    int maxVar() {\n      return offset;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ProbeDescriptor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport javax.xml.bind.annotation.XmlAttribute;\nimport javax.xml.bind.annotation.XmlElement;\nimport javax.xml.bind.annotation.XmlRootElement;\n\n@XmlRootElement(name = \"btrace-probes\")\npublic class ProbeDescriptor {\n  private final Map<String, OnProbe> nameToProbeMap;\n  private String namespace;\n  private Collection<OnProbe> probes;\n\n  public ProbeDescriptor() {\n    nameToProbeMap = new HashMap<>();\n  }\n\n  @XmlAttribute(name = \"namespace\")\n  public String getNamespace() {\n    return namespace;\n  }\n\n  public void setNamespace(String namespace) {\n    this.namespace = namespace;\n  }\n\n  @XmlElement(name = \"probe\")\n  public Collection<OnProbe> getProbes() {\n    return probes;\n  }\n\n  public void setProbes(Collection<OnProbe> probes) {\n    this.probes = probes;\n    for (OnProbe op : probes) {\n      nameToProbeMap.put(op.getName(), op);\n    }\n  }\n\n  public OnProbe findProbe(String name) {\n    return nameToProbeMap.get(name);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ProbeDescriptorLoader.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.InputStream;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport javax.xml.bind.JAXBContext;\nimport javax.xml.bind.JAXBException;\nimport javax.xml.bind.Unmarshaller;\nimport javax.xml.bind.helpers.DefaultValidationEventHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class loads BTrace probe descriptor XML files and caches the probe descriptions in a map.\n * The XML to object unmarshalling is done using JAXB.\n *\n * @author A. Sundararajan\n */\nfinal class ProbeDescriptorLoader {\n  private static final Logger log = LoggerFactory.getLogger(ProbeDescriptorLoader.class);\n\n  // cache for loaded probe descriptors\n  private static final Map<String, ProbeDescriptor> probeDescMap;\n\n  static {\n    probeDescMap = new ConcurrentHashMap<>();\n  }\n\n  // directories to search probe descriptor XML files.\n  private final String[] probeDescDirs;\n\n  ProbeDescriptorLoader(String probeDescPath) {\n    // split probe descriptor path into directories\n    probeDescDirs = probeDescPath != null ? probeDescPath.split(File.pathSeparator) : null;\n  }\n\n  ProbeDescriptor load(String namespace) {\n    // check in the cache\n    ProbeDescriptor res = probeDescMap.get(namespace);\n    if (res != null) {\n      if (log.isDebugEnabled()) {\n        log.debug(\"probe descriptor cache hit for namespace {}\", namespace);\n      }\n      return res;\n    } else {\n      // load probe descriptor for the given namespace\n      InputStream file = openDescriptor(namespace);\n      if (file == null) {\n        if (log.isDebugEnabled()) {\n          log.debug(\"didn't find probe descriptor file for namespace {}\", namespace);\n        }\n        return null;\n      }\n      ProbeDescriptor pd = load(file);\n      if (pd != null) {\n        if (log.isDebugEnabled()) {\n          log.debug(\"read probe descriptor for namespace {}\", namespace);\n        }\n        probeDescMap.put(namespace, pd);\n      }\n      return pd;\n    }\n  }\n\n  // unmarshall BTrace probe descriptor from XML\n  private ProbeDescriptor load(InputStream stream) {\n    try {\n      // Use this class's classloader to ensure JAXB finds jaxb.index from masked sections\n      JAXBContext jc =\n          JAXBContext.newInstance(\n              \"org.openjdk.btrace.core.annotations:org.openjdk.btrace.instr\",\n              ProbeDescriptorLoader.class.getClassLoader());\n      Unmarshaller u = jc.createUnmarshaller();\n      u.setEventHandler(new DefaultValidationEventHandler());\n      ProbeDescriptor pd = (ProbeDescriptor) u.unmarshal(stream);\n      pd.setProbes(pd.getProbes());\n      return pd;\n    } catch (JAXBException exp) {\n      log.debug(\"Failed to load a BTrace probe descriptor\", exp);\n      return null;\n    }\n  }\n\n  // look for <namespace>.xml file in each probe descriptor dir or on classpath\n  private InputStream openDescriptor(String namespace) {\n    InputStream is = null;\n    if (probeDescDirs != null) {\n      is = openDescriptorFromDirs(namespace);\n    }\n    if (is == null) {\n      is = openDescriptorFromClassPath(namespace);\n    }\n    if (is == null && log.isDebugEnabled()) {\n      log.debug(\"no probe descriptor found for namespace {}\", namespace);\n    }\n    return is;\n  }\n\n  private InputStream openDescriptorFromDirs(String namespace) {\n    String desc = namespace.trim() + \".xml\";\n    for (String dir : probeDescDirs) {\n      File f = new File(dir.trim(), desc);\n      if (log.isDebugEnabled())\n        log.debug(\n            \"looking for probe descriptor file '{}' ({}, {})\", f.getPath(), f.exists(), f.isFile());\n      if (f.exists() && f.isFile()) {\n        if (log.isDebugEnabled()) {\n          log.debug(\"probe descriptor for namespace {} is {}\", namespace, f);\n        }\n        try {\n          return new FileInputStream(f);\n        } catch (FileNotFoundException e) {\n          // ignore; never happens\n        }\n      }\n    }\n    return null;\n  }\n\n  private InputStream openDescriptorFromClassPath(String namespace) {\n    String target = Constants.EMBEDDED_BTRACE_SECTION_HEADER + namespace.trim() + \".xml\";\n    if (log.isDebugEnabled()) {\n      log.debug(\"looking for probe descriptor file '{}'\", target);\n    }\n    return ClassLoader.getSystemResourceAsStream(target);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ProbeDump.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport java.io.FileInputStream;\nimport java.nio.file.FileSystem;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport org.openjdk.btrace.core.SharedSettings;\n\npublic class ProbeDump {\n  public static void main(String[] args) throws Exception {\n    String path = args[0];\n\n    BTraceProbeFactory bpf = new BTraceProbeFactory(SharedSettings.GLOBAL);\n\n    BTraceProbe bp = bpf.createProbe(new FileInputStream(path));\n\n    FileSystem fs = FileSystems.getDefault();\n    Path p = fs.getPath(args[1]);\n    Files.write(\n        p.resolve(bp.getClassName().replace(\".\", \"_\") + \"_full.class\"), bp.getFullBytecode());\n    Files.write(\n        p.resolve(bp.getClassName().replace(\".\", \"_\") + \"_dh.class\"), bp.getDataHolderBytecode());\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ProbeRenameVisitor.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.ClassWriter;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\n\nfinal class ProbeRenameVisitor extends ClassVisitor {\n  private String oldClassName = null;\n  private final String newClassName;\n\n  ProbeRenameVisitor(ClassVisitor classVisitor, String newClassName) {\n    super(Opcodes.ASM9, classVisitor);\n    this.newClassName = newClassName.replace('.', '/');\n  }\n\n  static byte[] rename(String newClassName, byte[] data) {\n    ClassReader cr = new ClassReader(data);\n    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);\n    cr.accept(new ProbeRenameVisitor(cw, newClassName), ClassReader.SKIP_DEBUG);\n    return cw.toByteArray();\n  }\n\n  @Override\n  public void visit(\n      int version,\n      int access,\n      String name,\n      String signature,\n      String superName,\n      String[] interfaces) {\n    oldClassName = name;\n    super.visit(version, access, newClassName, signature, superName, interfaces);\n  }\n\n  @Override\n  public MethodVisitor visitMethod(\n      int access, String name, String descriptor, String signature, String[] exceptions) {\n    return new MethodVisitor(\n        Opcodes.ASM9, super.visitMethod(access, name, descriptor, signature, exceptions)) {\n      @Override\n      public void visitTypeInsn(int opcode, String type) {\n        super.visitTypeInsn(opcode, type.equals(oldClassName) ? newClassName : type);\n      }\n\n      @Override\n      public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {\n        super.visitFieldInsn(\n            opcode, owner.equals(oldClassName) ? newClassName : owner, name, descriptor);\n      }\n\n      @Override\n      public void visitMethodInsn(\n          int opcode, String owner, String name, String descriptor, boolean isInterface) {\n        super.visitMethodInsn(\n            opcode,\n            owner.equals(oldClassName) ? newClassName : owner,\n            name,\n            descriptor,\n            isInterface);\n      }\n\n      @Override\n      public void visitLdcInsn(Object value) {\n        // Rename class constants that reference the old class name\n        if (value instanceof Type) {\n          Type t = (Type) value;\n          if (t.getSort() == Type.OBJECT && t.getInternalName().equals(oldClassName)) {\n            super.visitLdcInsn(Type.getObjectType(newClassName));\n            return;\n          }\n        }\n        // Rename String constants that contain the old class name\n        if (value instanceof String) {\n          String s = (String) value;\n          String oldDotName = oldClassName.replace('/', '.');\n          String newDotName = newClassName.replace('/', '.');\n          if (s.equals(oldDotName)) {\n            super.visitLdcInsn(newDotName);\n            return;\n          }\n          if (s.equals(oldClassName)) {\n            super.visitLdcInsn(newClassName);\n            return;\n          }\n        }\n        super.visitLdcInsn(value);\n      }\n    };\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ProbeUpgradeVisitor_1_2.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport org.objectweb.asm.AnnotationVisitor;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.ClassWriter;\nimport org.objectweb.asm.FieldVisitor;\nimport org.objectweb.asm.MethodVisitor;\n\nfinal class ProbeUpgradeVisitor_1_2 extends ClassVisitor {\n\n  private static final String ANNOTATIONS_PREFIX_OLD = \"Lcom/sun/btrace/annotations/\";\n  private static final String ANNOTATIONS_PREFIX_NEW = \"Lorg/openjdk/btrace/core/annotations/\";\n\n  ProbeUpgradeVisitor_1_2(ClassVisitor cv) {\n    super(ASM9, cv);\n  }\n\n  private String cName = null;\n\n  static byte[] upgrade(ClassReader cr) {\n    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);\n    cr.accept(new ProbeUpgradeVisitor_1_2(cw), ClassReader.EXPAND_FRAMES);\n    return cw.toByteArray();\n  }\n\n  @Override\n  public void visit(\n      int version,\n      int access,\n      String name,\n      String signature,\n      String superName,\n      String[] interfaces) {\n    cName = name.replace('.', '/');\n    super.visit(version, access, name, signature, superName, interfaces);\n  }\n\n  @Override\n  public AnnotationVisitor visitAnnotation(String desc, boolean visible) {\n    if (desc.startsWith(ANNOTATIONS_PREFIX_OLD)) {\n      desc = ANNOTATIONS_PREFIX_NEW + desc.substring(ANNOTATIONS_PREFIX_OLD.length());\n    }\n    return super.visitAnnotation(desc, visible);\n  }\n\n  @Override\n  public FieldVisitor visitField(\n      int access, String name, String desc, String signature, Object value) {\n    if (desc.contains(\"BTraceRuntime\")) {\n      desc = Constants.BTRACERTACCESS_DESC;\n    }\n    return new FieldVisitor(ASM9, super.visitField(access, name, desc, signature, value)) {\n      @Override\n      public AnnotationVisitor visitAnnotation(String desc, boolean visible) {\n        if (desc.startsWith(ANNOTATIONS_PREFIX_OLD)) {\n          desc = ANNOTATIONS_PREFIX_NEW + desc.substring(ANNOTATIONS_PREFIX_OLD.length());\n        }\n        return super.visitAnnotation(desc, visible);\n      }\n    };\n  }\n\n  @Override\n  public MethodVisitor visitMethod(\n      int access, String name, String desc, String signature, String[] exceptions) {\n    return new MethodVisitor(ASM9, super.visitMethod(access, name, desc, signature, exceptions)) {\n      @Override\n      public AnnotationVisitor visitAnnotation(String desc, boolean visible) {\n        if (desc.startsWith(ANNOTATIONS_PREFIX_OLD)) {\n          desc = ANNOTATIONS_PREFIX_NEW + desc.substring(ANNOTATIONS_PREFIX_OLD.length());\n        }\n        return super.visitAnnotation(desc, visible);\n      }\n\n      @Override\n      public AnnotationVisitor visitParameterAnnotation(\n          int parameter, String desc, boolean visible) {\n        return super.visitParameterAnnotation(\n            parameter,\n            desc.replace(\"com/sun/btrace/annotations/\", \"org/openjdk/btrace/core/annotations/\"),\n            visible);\n      }\n\n      @Override\n      public void visitFieldInsn(int opcode, String owner, String name, String desc) {\n        if (desc.equals(\"Lcom/sun/btrace/BTraceRuntime;\")) {\n          desc = Constants.BTRACERTACCESS_DESC;\n        }\n        super.visitFieldInsn(opcode, owner, name, desc);\n      }\n\n      @Override\n      public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {\n        if (owner.equals(\"com/sun/btrace/BTraceRuntime\")) {\n          if (name.equals(\"enter\")) {\n            if (desc.equals(\"(Lcom/sun/btrace/BTraceRuntime;)Z\")) {\n              visitMethodInsn(\n                  INVOKESTATIC,\n                  Constants.BTRACERTACCESS_INTERNAL,\n                  name,\n                  \"(\" + Constants.BTRACERTACCESS_DESC + \")Z\",\n                  itf);\n            } else {\n              visitFieldInsn(GETSTATIC, cName, \"runtime\", Constants.BTRACERTACCESS_DESC);\n              visitMethodInsn(INVOKEVIRTUAL, Constants.BTRACERTACCESS_INTERNAL, name, \"()Z\", itf);\n            }\n          } else if (name.equals(\"forClass\")) {\n            desc = desc.replace(\"com/sun/btrace/shared/\", \"org/openjdk/btrace/core/handlers/\");\n            desc =\n                desc.replace(\n                    \")Lcom/sun/btrace/BTraceRuntime;\", \")\" + Constants.BTRACERTACCESS_DESC);\n            super.visitMethodInsn(opcode, Constants.BTRACERTACCESS_INTERNAL, name, desc, itf);\n          } else {\n            super.visitMethodInsn(INVOKESTATIC, Constants.BTRACERT_INTERNAL, name, desc, itf);\n          }\n        } else if (owner.startsWith(\"com/sun/btrace/BTraceUtils\")) {\n          super.visitMethodInsn(INVOKESTATIC, Constants.BTRACE_UTILS, name, desc, itf);\n        } else if (owner.startsWith(\"com/sun/btrace/services/\")) {\n          owner = owner.replace(\"com/sun/btrace/services/\", \"org/openjdk/btrace/services/\");\n          desc =\n              desc.replace(\n                  \"com/sun/btrace/BTraceRuntime\", \"org/openjdk/btrace/runtime/BTraceRuntimeAccess\");\n          super.visitMethodInsn(opcode, owner, name, desc, itf);\n        } else {\n          owner = owner.replace(\"com/sun/btrace/shared/\", \"org/openjdk/btrace/core/handlers/\");\n          super.visitMethodInsn(opcode, owner, name, desc, itf);\n        }\n      }\n\n      @Override\n      public void visitTypeInsn(int opcode, String type) {\n        type = type.replace(\"com/sun/btrace/shared/\", \"org/openjdk/btrace/core/handlers/\");\n        type = type.replace(\"com/sun/btrace/services/\", \"org/openjdk/btrace/services/\");\n        super.visitTypeInsn(opcode, type);\n      }\n    };\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/RandomIntProvider.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.instr.random.SharedRandomIntProvider;\nimport org.openjdk.btrace.instr.random.ThreadLocalRandomIntProvider;\n\n/**\n * @author Jaroslav Bachorik\n */\n@SuppressWarnings(\"LiteralClassName\")\npublic abstract class RandomIntProvider {\n  private static final RandomIntProvider rndIntProvider;\n  // for the testability purposes; BTraceRuntime initializes Unsafe instance\n  // and fails under JUnit\n  private static boolean useBtraceEnter = true;\n\n  static {\n    boolean entered = false;\n    try {\n      if (useBtraceEnter) {\n        entered = BTraceRuntime.enter();\n      }\n      Class<?> clz = null;\n      try {\n        clz = Class.forName(\"java.util.concurrent.ThreadLocalRandom\");\n      } catch (Throwable e) {\n        // ThreadLocalRandom not accessible -> pre JDK8\n      }\n      if (clz != null) {\n        rndIntProvider = new ThreadLocalRandomIntProvider();\n      } else {\n        //noinspection StaticInitializerReferencesSubClass\n        rndIntProvider = new SharedRandomIntProvider();\n      }\n    } finally {\n      if (entered) BTraceRuntime.leave();\n    }\n  }\n\n  protected RandomIntProvider() {}\n\n  public static RandomIntProvider getInstance() {\n    return rndIntProvider;\n  }\n\n  public abstract int nextInt(int bound);\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/SpecialParameterHolder.java",
    "content": "/*\n * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\n/**\n * A generalized super-class for various runtime classes representing the BTrace annotations\n *\n * @author Jaroslav Bachorik\n */\nabstract class SpecialParameterHolder {\n  private int selfParameter = -1;\n  private int methodParameter = -1;\n  private int classNameParameter = -1;\n  private int returnParameter = -1;\n  private int targetMethodOrFieldParameter = -1;\n  private int targetInstanceParameter = -1;\n  private int durationParameter = -1;\n\n  private boolean methodFqn = false;\n  private boolean targetMethodFqn = false;\n\n  public final int getSelfParameter() {\n    return selfParameter;\n  }\n\n  public final void setSelfParameter(int selfParameter) {\n    this.selfParameter = selfParameter;\n  }\n\n  public final int getClassNameParameter() {\n    return classNameParameter;\n  }\n\n  public final void setClassNameParameter(int classNameParameter) {\n    this.classNameParameter = classNameParameter;\n  }\n\n  public final int getMethodParameter() {\n    return methodParameter;\n  }\n\n  public final void setMethodParameter(int methodParameter) {\n    this.methodParameter = methodParameter;\n  }\n\n  public final boolean isMethodFqn() {\n    return methodFqn;\n  }\n\n  public final void setMethodFqn(boolean val) {\n    methodFqn = val;\n  }\n\n  public final boolean isTargetMethodOrFieldFqn() {\n    return targetMethodFqn;\n  }\n\n  public final void setTargetMethodOrFieldFqn(boolean val) {\n    targetMethodFqn = val;\n  }\n\n  public final int getReturnParameter() {\n    return returnParameter;\n  }\n\n  public final void setReturnParameter(int returnParameter) {\n    this.returnParameter = returnParameter;\n  }\n\n  public final int getTargetMethodOrFieldParameter() {\n    return targetMethodOrFieldParameter;\n  }\n\n  public final void setTargetMethodOrFieldParameter(int calledMethodParameter) {\n    targetMethodOrFieldParameter = calledMethodParameter;\n  }\n\n  public final int getTargetInstanceParameter() {\n    return targetInstanceParameter;\n  }\n\n  public final void setTargetInstanceParameter(int calledInstanceParameter) {\n    targetInstanceParameter = calledInstanceParameter;\n  }\n\n  public final int getDurationParameter() {\n    return durationParameter;\n  }\n\n  public final void setDurationParameter(int durationParameter) {\n    this.durationParameter = durationParameter;\n  }\n\n  public final void copyFrom(SpecialParameterHolder other) {\n    classNameParameter = other.classNameParameter;\n    durationParameter = other.durationParameter;\n    methodParameter = other.methodParameter;\n    returnParameter = other.returnParameter;\n    selfParameter = other.selfParameter;\n    targetInstanceParameter = other.targetInstanceParameter;\n    targetMethodOrFieldParameter = other.targetMethodOrFieldParameter;\n    methodFqn = other.methodFqn;\n    targetMethodFqn = other.targetMethodFqn;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/StackTrackingMethodVisitor.java",
    "content": "/*\n * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport org.objectweb.asm.Handle;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\n\n/**\n * This extended {@linkplain org.objectweb.asm.MethodVisitor} keeps track of the values currently on\n * the stack and their origin. This way it is eg. possible to allow invocation of virtual methods\n * only on instances obtained only through a certain factory method.\n *\n * @author Jaroslav Bachorik\n */\n@SuppressWarnings(\"DuplicateBranchesInSwitch\")\nclass StackTrackingMethodVisitor extends MethodVisitor {\n  private final State state;\n  private final Map<Label, Collection<Label>> tryCatchStart = new HashMap<>();\n  private final Map<Label, Collection<Label>> tryCatchEnd = new HashMap<>();\n  private final Set<Label> effectiveHandlers = new HashSet<>();\n  private final Collection<Label> handlers = new ArrayList<>();\n  private final Set<Label> visitedLabels = new HashSet<>();\n\n  public StackTrackingMethodVisitor(\n      MethodVisitor mv, String className, String desc, boolean isStatic) {\n    super(Opcodes.ASM9, mv);\n    Type[] args = Type.getArgumentTypes(desc);\n    state = new State(isStatic ? null : new InstanceItem(Type.getObjectType(className)), args);\n  }\n\n  @Override\n  public void visitMaxs(int maxStack, int maxLocals) {\n    super.visitMaxs(state.fState.maxStack, state.fState.maxVars);\n  }\n\n  @Override\n  public void visitMultiANewArrayInsn(String string, int i) {\n    super.visitMultiANewArrayInsn(string, i);\n  }\n\n  @Override\n  public void visitLookupSwitchInsn(Label label, int[] ints, Label[] labels) {\n    state.pop();\n    super.visitLookupSwitchInsn(label, ints, labels);\n  }\n\n  @Override\n  public void visitTableSwitchInsn(int i, int i1, Label label, Label... labels) {\n    state.pop();\n    super.visitTableSwitchInsn(i, i1, label, labels);\n  }\n\n  @Override\n  public void visitLdcInsn(Object o) {\n    ConstantItem ci = new ConstantItem(o);\n    state.push(ci);\n    if (o instanceof Long || o instanceof Double) {\n      state.push(ci);\n    }\n    super.visitLdcInsn(o);\n  }\n\n  @Override\n  public void visitJumpInsn(int opcode, Label label) {\n    super.visitJumpInsn(opcode, label);\n    switch (opcode) {\n      case Opcodes.IFEQ:\n      case Opcodes.IFGE:\n      case Opcodes.IFGT:\n      case Opcodes.IFLE:\n      case Opcodes.IFLT:\n      case Opcodes.IFNE:\n      case Opcodes.IFNONNULL:\n      case Opcodes.IFNULL:\n        {\n          state.pop();\n          state.branch(label);\n          break;\n        }\n      case Opcodes.IF_ACMPEQ:\n      case Opcodes.IF_ACMPNE:\n      case Opcodes.IF_ICMPEQ:\n      case Opcodes.IF_ICMPGE:\n      case Opcodes.IF_ICMPGT:\n      case Opcodes.IF_ICMPLE:\n      case Opcodes.IF_ICMPLT:\n      case Opcodes.IF_ICMPNE:\n        {\n          state.pop();\n          state.pop();\n          state.branch(label);\n          break;\n        }\n      case Opcodes.GOTO:\n      case Opcodes.JSR:\n        {\n          state.branch(label);\n          state.reset();\n          break;\n        }\n    }\n  }\n\n  @Override\n  public void visitInvokeDynamicInsn(String name, String desc, Handle handle, Object... bsmArgs) {\n    super.visitInvokeDynamicInsn(name, desc, handle, bsmArgs);\n\n    // Pop invokedynamic arguments (behaves like INVOKESTATIC)\n    Type[] args = Type.getArgumentTypes(desc);\n    for (int i = args.length - 1; i >= 0; i--) {\n      if (!args[i].equals(Type.VOID_TYPE)) {\n        switch (args[i].getSort()) {\n          case Type.LONG:\n          case Type.DOUBLE:\n            // category-2 consumes two slots\n            state.pop();\n            // fall through\n          case Type.INT:\n          case Type.FLOAT:\n          case Type.BOOLEAN:\n          case Type.CHAR:\n          case Type.SHORT:\n          case Type.BYTE:\n          case Type.ARRAY:\n          case Type.METHOD:\n          case Type.OBJECT:\n            state.pop();\n            break;\n        }\n      }\n    }\n\n    // Account for invokedynamic return value, if any\n    Type ret = Type.getReturnType(desc);\n    if (!ret.equals(Type.VOID_TYPE)) {\n      StackItem sl = new ResultItem(\"<indy>\", name, desc, ResultItem.Origin.METHOD, new StackItem[0]);\n      switch (ret.getSort()) {\n        case Type.LONG:\n        case Type.DOUBLE:\n          state.push(sl);\n          // fall through\n        case Type.INT:\n        case Type.FLOAT:\n        case Type.BOOLEAN:\n        case Type.CHAR:\n        case Type.SHORT:\n        case Type.BYTE:\n        case Type.ARRAY:\n        case Type.METHOD:\n        case Type.OBJECT:\n          state.push(sl);\n          break;\n      }\n    }\n  }\n\n  @Override\n  public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itfc) {\n    super.visitMethodInsn(opcode, owner, name, desc, itfc);\n\n    List<StackItem> poppedArgs = new ArrayList<>();\n    Type[] args = Type.getArgumentTypes(desc);\n    Type ret = Type.getReturnType(desc);\n\n    for (int i = args.length - 1; i >= 0; i--) {\n      if (!args[i].equals(Type.VOID_TYPE)) {\n        switch (args[i].getSort()) {\n          case Type.LONG:\n          case Type.DOUBLE:\n            {\n              state.pop();\n              // fall through\n            }\n          case Type.INT:\n          case Type.FLOAT:\n          case Type.BOOLEAN:\n          case Type.CHAR:\n          case Type.SHORT:\n          case Type.BYTE:\n          case Type.ARRAY:\n          case Type.METHOD:\n          case Type.OBJECT:\n            {\n              poppedArgs.add(state.pop());\n              break;\n            }\n        }\n      }\n    }\n\n    if (opcode != Opcodes.INVOKESTATIC) {\n      poppedArgs.add(state.pop());\n    }\n\n    if (!ret.equals(Type.VOID_TYPE)) {\n      StackItem sl =\n          new ResultItem(\n              owner, name, desc, ResultItem.Origin.METHOD, poppedArgs.toArray(new StackItem[0]));\n      switch (ret.getSort()) {\n        case Type.LONG:\n        case Type.DOUBLE:\n          {\n            state.push(sl);\n            // fall through\n          }\n        case Type.INT:\n        case Type.FLOAT:\n        case Type.BOOLEAN:\n        case Type.CHAR:\n        case Type.SHORT:\n        case Type.BYTE:\n        case Type.ARRAY:\n        case Type.METHOD:\n        case Type.OBJECT:\n          {\n            state.push(sl);\n            break;\n          }\n      }\n    }\n  }\n\n  @Override\n  public void visitFieldInsn(int opcode, String owner, String name, String desc) {\n    Type t = Type.getType(desc);\n    super.visitFieldInsn(opcode, owner, name, desc);\n\n    List<StackItem> parents = new ArrayList<>();\n    if (opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC) {\n      switch (t.getSort()) {\n        case Type.LONG:\n        case Type.DOUBLE:\n          {\n            state.pop();\n            // fall through\n          }\n        case Type.INT:\n        case Type.FLOAT:\n        case Type.BOOLEAN:\n        case Type.CHAR:\n        case Type.SHORT:\n        case Type.BYTE:\n        case Type.ARRAY:\n        case Type.METHOD:\n        case Type.OBJECT:\n          {\n            parents.add(state.pop());\n            break;\n          }\n      }\n    }\n    if (opcode == Opcodes.GETFIELD || opcode == Opcodes.PUTFIELD) {\n      parents.add(state.pop()); // pop 'this'\n    }\n    if (opcode == Opcodes.GETFIELD || opcode == Opcodes.GETSTATIC) {\n      StackItem sl =\n          new ResultItem(\n              owner, name, desc, ResultItem.Origin.FIELD, parents.toArray(new StackItem[0]));\n      switch (t.getSort()) {\n        case Type.LONG:\n        case Type.DOUBLE:\n          {\n            state.push(sl);\n            // fall through\n          }\n        case Type.INT:\n        case Type.FLOAT:\n        case Type.BOOLEAN:\n        case Type.CHAR:\n        case Type.SHORT:\n        case Type.BYTE:\n        case Type.ARRAY:\n        case Type.METHOD:\n        case Type.OBJECT:\n          {\n            state.push(sl);\n            break;\n          }\n      }\n    }\n  }\n\n  @Override\n  public void visitTypeInsn(int opcode, String type) {\n    super.visitTypeInsn(opcode, type);\n    switch (opcode) {\n      case Opcodes.NEW:\n        {\n          state.push(new InstanceItem(Type.getObjectType(type)));\n          break;\n        }\n      case Opcodes.ANEWARRAY:\n        {\n          state.push(new InstanceItem(Type.getObjectType(type), state.pop()));\n          break;\n        }\n      case Opcodes.INSTANCEOF:\n        {\n          state.push(new InstanceItem(Type.BOOLEAN_TYPE, state.pop()));\n          break;\n        }\n    }\n  }\n\n  @Override\n  public void visitVarInsn(int opcode, int var) {\n    super.visitVarInsn(opcode, var);\n    switch (opcode) {\n      case Opcodes.ILOAD:\n      case Opcodes.FLOAD:\n      case Opcodes.ALOAD:\n        {\n          state.push(state.load(var));\n          break;\n        }\n      case Opcodes.LLOAD:\n      case Opcodes.DLOAD:\n        {\n          StackItem sl = state.load(var);\n          state.push(sl);\n          state.push(sl);\n          break;\n        }\n      case Opcodes.ISTORE:\n      case Opcodes.FSTORE:\n      case Opcodes.ASTORE:\n        {\n          StackItem sl = state.pop();\n          state.store(sl, var);\n          break;\n        }\n      case Opcodes.LSTORE:\n      case Opcodes.DSTORE:\n        {\n          StackItem sl = state.pop();\n          state.pop();\n          state.store(sl, var);\n          break;\n        }\n    }\n  }\n\n  @Override\n  public void visitIntInsn(int opcode, int operand) {\n    super.visitIntInsn(opcode, operand);\n    switch (opcode) {\n      case Opcodes.BIPUSH:\n      case Opcodes.SIPUSH:\n        {\n          state.push(new ConstantItem(operand));\n          break;\n        }\n      case Opcodes.NEWARRAY:\n        {\n          StackItem sl = state.pop(); // size\n          state.push(new InstanceItem(Constants.OBJECT_TYPE, sl));\n          break;\n        }\n    }\n  }\n\n  @Override\n  public void visitInsn(int opcode) {\n    super.visitInsn(opcode);\n    switch (opcode) {\n      case Opcodes.ACONST_NULL:\n        {\n          state.push(new ConstantItem(null));\n          break;\n        }\n      case Opcodes.ICONST_0:\n        {\n          state.push(new ConstantItem(0));\n          break;\n        }\n      case Opcodes.ICONST_1:\n        {\n          state.push(new ConstantItem(1));\n          break;\n        }\n      case Opcodes.ICONST_2:\n        {\n          state.push(new ConstantItem(2));\n          break;\n        }\n      case Opcodes.ICONST_3:\n        {\n          state.push(new ConstantItem(3));\n          break;\n        }\n      case Opcodes.ICONST_4:\n        {\n          state.push(new ConstantItem(4));\n          break;\n        }\n      case Opcodes.ICONST_5:\n        {\n          state.push(new ConstantItem(5));\n          break;\n        }\n      case Opcodes.ICONST_M1:\n        {\n          state.push(new ConstantItem(-1));\n          break;\n        }\n      case Opcodes.FCONST_0:\n        {\n          state.push(new ConstantItem(0f));\n          break;\n        }\n      case Opcodes.FCONST_1:\n        {\n          state.push(new ConstantItem(1f));\n          break;\n        }\n      case Opcodes.FCONST_2:\n        {\n          state.push(new ConstantItem(2f));\n          break;\n        }\n      case Opcodes.LCONST_0:\n        {\n          StackItem si = new ConstantItem(0L);\n          state.push(si);\n          state.push(si);\n          break;\n        }\n      case Opcodes.LCONST_1:\n        {\n          StackItem si = new ConstantItem(1L);\n          state.push(si);\n          state.push(si);\n          break;\n        }\n      case Opcodes.DCONST_0:\n        {\n          StackItem si = new ConstantItem(0d);\n          state.push(si);\n          state.push(si);\n          break;\n        }\n      case Opcodes.DCONST_1:\n        {\n          StackItem si = new ConstantItem(1d);\n          state.push(si);\n          state.push(si);\n          break;\n        }\n      case Opcodes.AALOAD:\n        {\n          StackItem index = state.pop();\n          StackItem ref = state.pop();\n\n          Type t = null;\n          if (ref.getKind() == StackItem.Kind.INSTANCE) {\n            t = ((InstanceItem) ref).getType();\n          } else if (ref.getKind() == StackItem.Kind.RESULT) {\n            t = ((ResultItem) ref).getType();\n          }\n\n          state.push(new InstanceItem(t, ref, index));\n          break;\n        }\n      case Opcodes.IALOAD:\n        {\n          StackItem index = state.pop();\n          StackItem ref = state.pop();\n\n          state.push(new InstanceItem(Type.INT_TYPE, index, ref));\n          break;\n        }\n      case Opcodes.FALOAD:\n        {\n          StackItem index = state.pop();\n          StackItem ref = state.pop();\n\n          state.push(new InstanceItem(Type.FLOAT_TYPE, index, ref));\n          break;\n        }\n      case Opcodes.BALOAD:\n        {\n          StackItem index = state.pop();\n          StackItem ref = state.pop();\n\n          state.push(new InstanceItem(Type.BYTE_TYPE, index, ref));\n          break;\n        }\n      case Opcodes.CALOAD:\n        {\n          StackItem index = state.pop();\n          StackItem ref = state.pop();\n\n          state.push(new InstanceItem(Type.CHAR_TYPE, index, ref));\n          break;\n        }\n      case Opcodes.SALOAD:\n        {\n          StackItem index = state.pop();\n          StackItem ref = state.pop();\n\n          state.push(new InstanceItem(Type.SHORT_TYPE, index, ref));\n          break;\n        }\n      case Opcodes.LALOAD:\n        {\n          StackItem index = state.pop();\n          StackItem ref = state.pop();\n\n          StackItem sl = new InstanceItem(Type.LONG_TYPE, index, ref);\n          state.push(sl);\n          state.push(sl);\n          break;\n        }\n      case Opcodes.DALOAD:\n        {\n          StackItem index = state.pop();\n          StackItem ref = state.pop();\n\n          StackItem sl = new InstanceItem(Type.DOUBLE_TYPE, index, ref);\n          state.push(sl);\n          state.push(sl);\n          break;\n        }\n      case Opcodes.AASTORE:\n      case Opcodes.IASTORE:\n      case Opcodes.FASTORE:\n      case Opcodes.BASTORE:\n      case Opcodes.CASTORE:\n      case Opcodes.SASTORE:\n        {\n          state.pop(); // val\n          state.pop(); // index\n          state.pop(); // arrayref\n\n          break;\n        }\n      case Opcodes.LASTORE:\n      case Opcodes.DASTORE:\n        {\n          state.pop();\n          state.pop(); // var\n          state.pop(); // index\n          state.pop(); // arrayref\n\n          break;\n        }\n      case Opcodes.POP:\n        {\n          state.pop();\n          break;\n        }\n      case Opcodes.POP2:\n        {\n          state.pop();\n          state.pop();\n          break;\n        }\n      case Opcodes.DUP:\n        {\n          state.push(state.peek());\n          break;\n        }\n      case Opcodes.DUP_X1:\n        {\n          StackItem x = state.pop();\n          StackItem y = state.pop();\n          state.push(x);\n          state.push(y);\n          state.push(x);\n          break;\n        }\n      case Opcodes.DUP_X2:\n        {\n          StackItem x = state.pop();\n          StackItem y = state.pop();\n          StackItem z = state.pop();\n          state.push(x);\n          state.push(z);\n          state.push(y);\n          state.push(x);\n          break;\n        }\n      case Opcodes.DUP2:\n        {\n          StackItem x = state.pop();\n          StackItem y = state.peek();\n          state.push(x);\n          state.push(y);\n          state.push(x);\n          break;\n        }\n      case Opcodes.DUP2_X1:\n        {\n          StackItem x2 = state.pop();\n          StackItem x1 = state.pop();\n          StackItem y = state.pop();\n          state.push(x1);\n          state.push(x2);\n          state.push(y);\n          state.push(x1);\n          state.push(x2);\n          break;\n        }\n      case Opcodes.DUP2_X2:\n        {\n          StackItem x2 = state.pop();\n          StackItem x1 = state.pop();\n          StackItem y2 = state.pop();\n          StackItem y1 = state.pop();\n          state.push(x1);\n          state.push(x2);\n          state.push(y1);\n          state.push(y2);\n          state.push(x1);\n          state.push(x2);\n          break;\n        }\n      case Opcodes.SWAP:\n        {\n          StackItem x = state.pop();\n          StackItem y = state.pop();\n          state.push(x);\n          state.push(y);\n          break;\n        }\n      case Opcodes.IADD:\n      case Opcodes.ISUB:\n      case Opcodes.IMUL:\n      case Opcodes.IDIV:\n      case Opcodes.IREM:\n      case Opcodes.IAND:\n      case Opcodes.IOR:\n      case Opcodes.IXOR:\n      case Opcodes.ISHR:\n      case Opcodes.ISHL:\n      case Opcodes.IUSHR:\n        {\n          StackItem x = state.pop();\n          StackItem y = state.pop();\n          state.push(new InstanceItem(Type.INT_TYPE, x, y));\n          break;\n        }\n      case Opcodes.FADD:\n      case Opcodes.FSUB:\n      case Opcodes.FMUL:\n      case Opcodes.FDIV:\n      case Opcodes.FREM:\n        {\n          StackItem x = state.pop();\n          StackItem y = state.pop();\n          state.push(new InstanceItem(Type.FLOAT_TYPE, x, y));\n          break;\n        }\n      case Opcodes.LADD:\n      case Opcodes.LSUB:\n      case Opcodes.LMUL:\n      case Opcodes.LDIV:\n      case Opcodes.LREM:\n      case Opcodes.LAND:\n      case Opcodes.LOR:\n      case Opcodes.LXOR:\n      case Opcodes.LSHR:\n      case Opcodes.LSHL:\n      case Opcodes.LUSHR:\n        {\n          StackItem x = state.pop();\n          state.pop();\n          StackItem y = state.pop();\n          state.pop();\n          StackItem rslt = new InstanceItem(Type.LONG_TYPE, x, y);\n          state.push(rslt);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.DADD:\n      case Opcodes.DSUB:\n      case Opcodes.DMUL:\n      case Opcodes.DDIV:\n      case Opcodes.DREM:\n        {\n          StackItem x = state.pop();\n          state.pop();\n          StackItem y = state.pop();\n          state.pop();\n          StackItem rslt = new InstanceItem(Type.DOUBLE_TYPE, x, y);\n          state.push(rslt);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.I2L:\n        {\n          StackItem x = state.pop();\n          StackItem rslt = new InstanceItem(Type.LONG_TYPE, x);\n          state.push(rslt);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.I2F:\n        {\n          StackItem x = state.pop();\n          StackItem rslt = new InstanceItem(Type.FLOAT_TYPE, x);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.I2B:\n        {\n          StackItem x = state.pop();\n          Set<StackItem> parents = new HashSet<>(x.getParents());\n          StackItem rslt = new InstanceItem(Type.BYTE_TYPE, parents.toArray(new StackItem[0]));\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.I2C:\n        {\n          StackItem x = state.pop();\n          StackItem rslt = new InstanceItem(Type.CHAR_TYPE, x);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.I2S:\n        {\n          StackItem x = state.pop();\n          StackItem rslt = new InstanceItem(Type.SHORT_TYPE, x);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.I2D:\n        {\n          StackItem x = state.pop();\n          StackItem rslt = new InstanceItem(Type.DOUBLE_TYPE, x);\n          state.push(rslt);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.L2I:\n        {\n          StackItem x = state.pop();\n          state.pop();\n          StackItem rslt = new InstanceItem(Type.INT_TYPE, x);\n          state.push(rslt);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.L2F:\n        {\n          StackItem x = state.pop();\n          state.pop();\n          StackItem rslt = new InstanceItem(Type.FLOAT_TYPE, x);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.L2D:\n        {\n          StackItem x = state.pop();\n          state.pop();\n          StackItem rslt = new InstanceItem(Type.DOUBLE_TYPE, x);\n          state.push(rslt);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.F2I:\n        {\n          StackItem x = state.pop();\n          StackItem rslt = new InstanceItem(Type.INT_TYPE, x);\n          state.push(rslt);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.F2L:\n        {\n          StackItem x = state.pop();\n          StackItem rslt = new InstanceItem(Type.LONG_TYPE, x);\n          state.push(rslt);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.F2D:\n        {\n          StackItem x = state.pop();\n          StackItem rslt = new InstanceItem(Type.DOUBLE_TYPE, x);\n          state.push(rslt);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.D2I:\n        {\n          StackItem x = state.pop();\n          state.pop();\n          StackItem rslt = new InstanceItem(Type.INT_TYPE, x);\n          state.push(rslt);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.D2F:\n        {\n          StackItem x = state.pop();\n          state.pop();\n          StackItem rslt = new InstanceItem(Type.FLOAT_TYPE, x);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.D2L:\n        {\n          StackItem x = state.pop();\n          state.pop();\n          StackItem rslt = new InstanceItem(Type.LONG_TYPE, x);\n          state.push(rslt);\n          state.push(rslt);\n          break;\n        }\n      case Opcodes.LCMP:\n        {\n          StackItem a = state.pop();\n          StackItem b = state.pop();\n          StackItem c = state.pop();\n          StackItem d = state.pop();\n\n          state.push(new InstanceItem(Type.INT_TYPE, a, b, c, d));\n          break;\n        }\n      case Opcodes.FCMPL:\n      case Opcodes.FCMPG:\n        {\n          StackItem x = state.pop();\n          StackItem y = state.pop();\n\n          state.push(new InstanceItem(Type.INT_TYPE, x, y));\n          break;\n        }\n      case Opcodes.DCMPL:\n      case Opcodes.DCMPG:\n        {\n          StackItem a = state.pop();\n          StackItem b = state.pop();\n          StackItem c = state.pop();\n          StackItem d = state.pop();\n\n          state.push(new InstanceItem(Type.INT_TYPE, a, b, c, d));\n          break;\n        }\n      case Opcodes.IRETURN:\n      case Opcodes.LRETURN:\n      case Opcodes.FRETURN:\n      case Opcodes.DRETURN:\n      case Opcodes.ARETURN:\n      case Opcodes.RETURN:\n      case Opcodes.RET:\n        {\n          state.reset();\n          break;\n        }\n      case Opcodes.ATHROW:\n        {\n          for (Label l : effectiveHandlers) {\n            state.branch(l);\n          }\n          state.reset();\n          break;\n        }\n      case Opcodes.ARRAYLENGTH:\n        {\n          Set<StackItem> parents = new HashSet<>(state.pop().getParents());\n          state.push(new InstanceItem(Type.INT_TYPE, parents.toArray(new StackItem[0])));\n          break;\n        }\n      case Opcodes.MONITORENTER:\n      case Opcodes.MONITOREXIT:\n        {\n          state.pop();\n          break;\n        }\n    }\n  }\n\n  @Override\n  public void visitIincInsn(int var, int inc) {\n    StackItem si = state.load(var);\n    state.store(new InstanceItem(Type.INT_TYPE, si), var);\n    super.visitIincInsn(var, inc);\n  }\n\n  @Override\n  public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {\n    super.visitTryCatchBlock(start, end, handler, type);\n    Collection<Label> labels = tryCatchStart.computeIfAbsent(start, k -> new ArrayList<>());\n    labels.add(handler);\n\n    addToMappedCollection(tryCatchStart, start, handler);\n    addToMappedCollection(tryCatchEnd, end, handler);\n\n    handlers.add(handler);\n  }\n\n  private void addToMappedCollection(Map<Label, Collection<Label>> map, Label l, Label handler) {\n    Collection<Label> labels = map.computeIfAbsent(l, k -> new ArrayList<>());\n    labels.add(handler);\n  }\n\n  @Override\n  public void visitLabel(Label label) {\n    super.visitLabel(label);\n    Collection<Label> labels = tryCatchStart.get(label);\n    if (labels != null) {\n      effectiveHandlers.addAll(labels);\n    } else {\n      labels = tryCatchEnd.get(label);\n      if (labels != null) {\n        effectiveHandlers.removeAll(labels);\n      }\n      state.join(label);\n      if (handlers.contains(label)) {\n        state.push(new InstanceItem(Constants.THROWABLE_TYPE));\n      }\n    }\n    visitedLabels.add(label);\n  }\n\n  protected List<StackItem> getMethodParams(String desc, boolean isStatic) {\n    Type[] argTypes = Type.getArgumentTypes(desc);\n    int idx = argTypes.length - 1;\n\n    List<StackItem> items = new ArrayList<>();\n    Iterator<StackItem> it = state.fState.stack.iterator();\n    while (it.hasNext() && idx >= 0) {\n      Type t = argTypes[idx];\n      items.add(0, it.next());\n      if (t.equals(Type.LONG_TYPE) || t.equals(Type.DOUBLE_TYPE)) {\n        it.next();\n      }\n      idx--;\n    }\n    if (!isStatic && it.hasNext()) {\n      items.add(0, it.next());\n    }\n    return items;\n  }\n\n  public abstract static class StackItem {\n    private final Set<StackItem> parents = new HashSet<>();\n\n    public StackItem(StackItem... parents) {\n      this.parents.addAll(Arrays.asList(parents));\n    }\n\n    public final Set<StackItem> getParents() {\n      return parents;\n    }\n\n    public final void merge(StackItem sl) {\n      parents.addAll(sl.getParents());\n    }\n\n    public abstract Kind getKind();\n\n    public enum Kind {\n      VARIABLE,\n      CONSTANT,\n      INSTANCE,\n      RESULT\n    }\n  }\n\n  public static final class VariableItem extends StackItem {\n    private final int var;\n\n    public VariableItem(int var, StackItem... parents) {\n      super(parents);\n      this.var = var;\n    }\n\n    public int getVar() {\n      return var;\n    }\n\n    @Override\n    public Kind getKind() {\n      return Kind.VARIABLE;\n    }\n\n    @Override\n    public int hashCode() {\n      int hash = 5;\n      hash = 31 * hash + var;\n      return hash;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n      if (obj == null) {\n        return false;\n      }\n      if (getClass() != obj.getClass()) {\n        return false;\n      }\n      VariableItem other = (VariableItem) obj;\n      return var == other.var;\n    }\n  }\n\n  public static class ConstantItem extends StackItem {\n    private final Object val;\n\n    public ConstantItem(Object val, StackItem... parents) {\n      super(parents);\n      this.val = val;\n    }\n\n    public Object getValue() {\n      return val;\n    }\n\n    @Override\n    public Kind getKind() {\n      return Kind.CONSTANT;\n    }\n\n    @Override\n    public int hashCode() {\n      int hash = 7;\n      hash = 59 * hash + (val != null ? val.hashCode() : 0);\n      return hash;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n      if (obj == null) {\n        return false;\n      }\n      if (getClass() != obj.getClass()) {\n        return false;\n      }\n      ConstantItem other = (ConstantItem) obj;\n      return !(!Objects.equals(val, other.val));\n    }\n  }\n\n  public static class InstanceItem extends StackItem {\n    private final Type t;\n\n    public InstanceItem(Type t, StackItem... parents) {\n      super(parents);\n      this.t = t;\n    }\n\n    public Type getType() {\n      return t;\n    }\n\n    @Override\n    public Kind getKind() {\n      return Kind.INSTANCE;\n    }\n\n    @Override\n    public int hashCode() {\n      int hash = 7;\n      hash = 41 * hash + (t != null ? t.hashCode() : 0);\n      return hash;\n    }\n\n    @Override\n    @SuppressWarnings(\"ReferenceEquality\")\n    public boolean equals(Object obj) {\n      if (obj == null) {\n        return false;\n      }\n      if (getClass() != obj.getClass()) {\n        return false;\n      }\n      InstanceItem other = (InstanceItem) obj;\n      return !(!Objects.equals(t, other.t));\n    }\n  }\n\n  public static class ResultItem extends StackItem {\n    private final String owner, name, desc;\n    private final Origin origin;\n\n    public ResultItem(String owner, String name, String desc, Origin origin, StackItem... parents) {\n      super(parents);\n      this.owner = owner;\n      this.name = name;\n      this.desc = desc;\n      this.origin = origin;\n    }\n\n    public String getOwner() {\n      return owner;\n    }\n\n    public String getName() {\n      return name;\n    }\n\n    public String getDesc() {\n      return desc;\n    }\n\n    public Type getType() {\n      return Type.getReturnType(desc);\n    }\n\n    public Origin getOrigin() {\n      return origin;\n    }\n\n    @Override\n    public Kind getKind() {\n      return Kind.RESULT;\n    }\n\n    @Override\n    public int hashCode() {\n      int hash = 7;\n      hash = 89 * hash + (owner != null ? owner.hashCode() : 0);\n      hash = 89 * hash + (name != null ? name.hashCode() : 0);\n      hash = 89 * hash + (desc != null ? desc.hashCode() : 0);\n      return hash;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n      if (obj == null) {\n        return false;\n      }\n      if (getClass() != obj.getClass()) {\n        return false;\n      }\n      ResultItem other = (ResultItem) obj;\n      if (!Objects.equals(owner, other.owner)) {\n        return false;\n      }\n      if (!Objects.equals(name, other.name)) {\n        return false;\n      }\n      return Objects.equals(desc, other.desc);\n    }\n\n    public enum Origin {\n      FIELD,\n      METHOD\n    }\n  }\n\n  private static final class FrameState {\n    private final Map<Integer, StackItem> vars;\n    private final Map<Integer, StackItem> args;\n    private final Deque<StackItem> stack;\n    private int maxStack;\n    private int maxVars;\n\n    FrameState(Map<Integer, StackItem> args) {\n      this(new LinkedList<>(), null, args);\n    }\n\n    private FrameState(\n        Deque<StackItem> s, Map<Integer, StackItem> v, Map<Integer, StackItem> args) {\n      stack = new LinkedList<>(s);\n      vars = v != null ? new HashMap<>(v) : new HashMap<>();\n      this.args = new HashMap<>(args);\n    }\n\n    public StackItem peek() {\n      return stack.peek();\n    }\n\n    public void push(StackItem sl) {\n      stack.push(sl);\n      maxStack = Math.max(stack.size(), maxStack);\n    }\n\n    public StackItem pop() {\n      return stack.pop();\n    }\n\n    public void store(StackItem si, int index) {\n      vars.put(index, si);\n      updateMaxVars(si, index);\n    }\n\n    public StackItem load(int index) {\n      StackItem si = vars.get(index);\n      if (si == null) {\n        si = args.get(index);\n      }\n      updateMaxVars(si, index);\n      return si;\n    }\n\n    public FrameState duplicate() {\n      return new FrameState(stack, vars, args);\n    }\n\n    public boolean isEmpty() {\n      return stack.isEmpty();\n    }\n\n    public void reset() {\n      stack.clear();\n      vars.clear();\n    }\n\n    private void updateMaxVars(StackItem si, int index) {\n      if (si == null) {\n        return;\n      }\n      int size = 1;\n      switch (si.getKind()) {\n        case INSTANCE:\n          {\n            size = ((InstanceItem) si).getType().getSize();\n            break;\n          }\n        case RESULT:\n          {\n            size = ((ResultItem) si).getType().getSize();\n            break;\n          }\n        case CONSTANT:\n          {\n            Object val = ((ConstantItem) si).getValue();\n            if (val instanceof Double || val instanceof Long) {\n              size = 2;\n            }\n            break;\n          }\n      }\n      maxVars = Math.max(index + size, maxVars);\n    }\n  }\n\n  private final class State {\n    private final Map<Label, Set<FrameState>> stateMap = new HashMap<>();\n\n    private FrameState fState;\n\n    public State(InstanceItem receiver, Type[] args) {\n      Map<Integer, StackItem> argMap = new HashMap<>();\n      int index = 0;\n      if (receiver != null) {\n        argMap.put(index++, receiver);\n      }\n      for (Type t : args) {\n        argMap.put(index++, new InstanceItem(t));\n        if (t.equals(Type.LONG_TYPE) || t.equals(Type.DOUBLE_TYPE)) {\n          index++;\n        }\n      }\n\n      fState = new FrameState(argMap);\n    }\n\n    public void branch(Label l) {\n      if (visitedLabels.contains(l)) return; // back loop should preserve the stack\n\n      Set<FrameState> states = stateMap.computeIfAbsent(l, k -> new HashSet<>());\n      states.add(fState.duplicate());\n    }\n\n    public void branch(Label l, Type throwable) {\n      if (visitedLabels.contains(l)) return; // back loop should preserve the stack\n\n      Set<FrameState> states = stateMap.computeIfAbsent(l, k -> new HashSet<>());\n      FrameState duplicated = fState.duplicate();\n      duplicated.push(new InstanceItem(throwable));\n      states.add(duplicated);\n    }\n\n    public void join(Label l) {\n      Set<FrameState> states = stateMap.remove(l);\n      if (states != null) {\n        if (fState.isEmpty() && !states.isEmpty()) {\n          FrameState s = states.iterator().next();\n          if (!s.isEmpty()) {\n            fState = s;\n          }\n        }\n        for (FrameState fs : states) {\n          Iterator<StackItem> i1 = fState.stack.iterator();\n          Iterator<StackItem> i2 = fs.stack.iterator();\n\n          while (i1.hasNext()) {\n            if (i2.hasNext()) {\n              StackItem target = i1.next();\n              StackItem src = i2.next();\n\n              target.merge(src);\n            } else {\n              throw new IllegalStateException(\"Error merging simulated stack\");\n            }\n          }\n          if (i2.hasNext()) {\n            throw new IllegalStateException(\"Error merging simulated stack\");\n          }\n        }\n      }\n    }\n\n    public StackItem peek() {\n      return fState.peek();\n    }\n\n    public void push(StackItem sl) {\n      fState.push(sl);\n    }\n\n    public StackItem pop() {\n      return fState.pop();\n    }\n\n    public void store(StackItem sl, int index) {\n      fState.store(sl, index);\n    }\n\n    public StackItem load(int index) {\n      return fState.load(index);\n    }\n\n    public void reset() {\n      fState.reset();\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/SynchronizedInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * This visitor helps in inserting code whenever a synchronized method or block is about to be\n * entered/exited. The code to insert on synchronized method or block entry/exit may be decided by\n * derived class. By default, this class inserts code to print a message.\n *\n * @author A. Sundararajan\n */\npublic class SynchronizedInstrumentor extends MethodEntryExitInstrumentor {\n\n  protected final boolean isStatic;\n  protected final boolean isSyncMethod;\n\n  public SynchronizedInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n\n    isStatic = (access & ACC_STATIC) != 0;\n    isSyncMethod = (access & ACC_SYNCHRONIZED) != 0;\n  }\n\n  @Override\n  protected void onMethodEntry() {\n    if (isSyncMethod) {\n      onAfterSyncEntry();\n    }\n  }\n\n  @Override\n  protected void onMethodReturn(int opcode) {\n    onErrorReturn();\n  }\n\n  @Override\n  protected void onErrorReturn() {\n    if (isSyncMethod) {\n      onBeforeSyncExit();\n    }\n  }\n\n  @Override\n  public void visitInsn(int opcode) {\n    if (opcode == MONITORENTER) {\n      onBeforeSyncEntry();\n    } else if (opcode == MONITOREXIT) {\n      onBeforeSyncExit();\n    }\n    super.visitInsn(opcode);\n    if (opcode == MONITORENTER) {\n      onAfterSyncEntry();\n    } else if (opcode == MONITOREXIT) {\n      onAfterSyncExit();\n    }\n  }\n\n  protected void onBeforeSyncEntry() {\n    asm.println(\"before synchronized entry\");\n  }\n\n  protected void onAfterSyncEntry() {\n    asm.println(\"after synchronized entry\");\n  }\n\n  protected void onBeforeSyncExit() {\n    asm.println(\"before synchronized exit\");\n  }\n\n  protected void onAfterSyncExit() {\n    asm.println(\"after synchronized exit\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/ThrowInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * This visitor helps in inserting code whenever an exception is about to be thrown. The code to\n * insert on exception throw may be decided by derived class. By default, this class inserts code to\n * print stack trace of the exception thrown.\n *\n * @author A. Sundararajan\n */\npublic class ThrowInstrumentor extends MethodInstrumentor {\n  public ThrowInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  public void visitInsn(int opcode) {\n    if (opcode == ATHROW) {\n      onThrow();\n    }\n    super.visitInsn(opcode);\n  }\n\n  protected void onThrow() {\n    visitInsn(DUP);\n    visitMethodInsn(INVOKEVIRTUAL, \"java/lang/Throwable\", \"printStackTrace\", \"()V\", false);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/TypeCheckInstrumentor.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.CHECKCAST;\nimport static org.objectweb.asm.Opcodes.INSTANCEOF;\n\nimport org.objectweb.asm.MethodVisitor;\n\n/**\n * This class helps in inserting code whenever a type check (instanceof or checkcast) is done. The\n * code to insert on type check may be decided by derived class. By default, this class inserts code\n * to print message.\n *\n * @author A. Sundararajan\n */\npublic class TypeCheckInstrumentor extends MethodInstrumentor {\n  public TypeCheckInstrumentor(\n      ClassLoader cl,\n      MethodVisitor mv,\n      MethodInstrumentorHelper mHelper,\n      String parentClz,\n      String superClz,\n      int access,\n      String name,\n      String desc) {\n    super(cl, mv, mHelper, parentClz, superClz, access, name, desc);\n  }\n\n  @Override\n  public void visitTypeInsn(int opcode, String desc) {\n    boolean typeCheck = (opcode == CHECKCAST || opcode == INSTANCEOF);\n    if (typeCheck) {\n      onBeforeTypeCheck(opcode, desc);\n    }\n    super.visitTypeInsn(opcode, desc);\n    if (typeCheck) {\n      onAfterTypeCheck(opcode, desc);\n    }\n  }\n\n  protected void onBeforeTypeCheck(int opcode, String desc) {\n    asm.println(\"before type checking for \" + desc);\n  }\n\n  protected void onAfterTypeCheck(int opcode, String desc) {\n    asm.println(\"after type checking for \" + desc);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/TypeUtils.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.StringTokenizer;\nimport org.objectweb.asm.Type;\nimport org.openjdk.btrace.core.types.AnyType;\n\npublic final class TypeUtils {\n  public static final Type objectArrayType = Type.getType(Object[].class);\n  public static final Type anyTypeArray = Type.getType(AnyType[].class);\n  private static final Map<String, String> primitives;\n\n  static {\n    primitives = new HashMap<>();\n    primitives.put(\"void\", \"V\");\n    primitives.put(\"byte\", \"B\");\n    primitives.put(\"char\", \"C\");\n    primitives.put(\"double\", \"D\");\n    primitives.put(\"float\", \"F\");\n    primitives.put(\"int\", \"I\");\n    primitives.put(\"long\", \"J\");\n    primitives.put(\"short\", \"S\");\n    primitives.put(\"boolean\", \"Z\");\n  }\n\n  private TypeUtils() {}\n\n  public static boolean isPrimitive(String typeDesc) {\n    if (typeDesc.length() == 1) {\n      switch (typeDesc.charAt(0)) {\n        case 'I':\n        case 'J':\n        case 'F':\n        case 'D':\n        case 'Z':\n        case 'C':\n        case 'B':\n          {\n            return true;\n          }\n      }\n    }\n    return false;\n  }\n\n  @SuppressWarnings(\"ReferenceEquality\")\n  public static boolean isPrimitive(Type t) {\n    return t == Type.BOOLEAN_TYPE\n        || t == Type.BYTE_TYPE\n        || t == Type.CHAR_TYPE\n        || t == Type.DOUBLE_TYPE\n        || t == Type.FLOAT_TYPE\n        || t == Type.INT_TYPE\n        || t == Type.LONG_TYPE\n        || t == Type.SHORT_TYPE;\n  }\n\n  public static boolean isAnyType(Type t) {\n    return t.equals(Constants.ANYTYPE_TYPE);\n  }\n\n  public static boolean isAnyTypeArray(Type t) {\n    return t.equals(anyTypeArray);\n  }\n\n  public static boolean isObject(Type t) {\n    return t.equals(Constants.OBJECT_TYPE);\n  }\n\n  public static boolean isObjectOrAnyType(Type t) {\n    return isObject(t) || isAnyType(t);\n  }\n\n  public static boolean isString(Type t) {\n    return t.equals(Constants.STRING_TYPE);\n  }\n\n  public static boolean isArray(Type t) {\n    return t.getSort() == Type.ARRAY;\n  }\n\n  public static boolean isThrowable(Type t) {\n    return t.equals(Constants.THROWABLE_TYPE);\n  }\n\n  public static boolean isVoid(Type t) {\n    return Type.VOID_TYPE.equals(t) || Constants.VOIDREF_TYPE.equals(t);\n  }\n\n  public static Type getArrayType(int arrayOpcode) {\n    switch (arrayOpcode) {\n      case IALOAD:\n      case IASTORE:\n        return Type.getType(\"[I\");\n\n      case BALOAD:\n      case BASTORE:\n        return Type.getType(\"[B\");\n\n      case AALOAD:\n      case AASTORE:\n        return objectArrayType;\n\n      case CALOAD:\n      case CASTORE:\n        return Type.getType(\"[C\");\n\n      case FALOAD:\n      case FASTORE:\n        return Type.getType(\"[F\");\n\n      case SALOAD:\n      case SASTORE:\n        return Type.getType(\"[S\");\n\n      case LALOAD:\n      case LASTORE:\n        return Type.getType(\"[J\");\n\n      case DALOAD:\n      case DASTORE:\n        return Type.getType(\"[D\");\n\n      default:\n        throw new InstrumentationException(\n            String.format(\"Invalid array opcode in getArrayType: 0x%02X\", arrayOpcode));\n    }\n  }\n\n  public static Type getElementType(int arrayOpcode) {\n    switch (arrayOpcode) {\n      case IALOAD:\n      case IASTORE:\n        return Type.INT_TYPE;\n\n      case BALOAD:\n      case BASTORE:\n        return Type.BYTE_TYPE;\n\n      case AALOAD:\n      case AASTORE:\n        return Constants.OBJECT_TYPE;\n\n      case CALOAD:\n      case CASTORE:\n        return Type.CHAR_TYPE;\n\n      case FALOAD:\n      case FASTORE:\n        return Type.FLOAT_TYPE;\n\n      case SALOAD:\n      case SASTORE:\n        return Type.SHORT_TYPE;\n\n      case LALOAD:\n      case LASTORE:\n        return Type.LONG_TYPE;\n\n      case DALOAD:\n      case DASTORE:\n        return Type.DOUBLE_TYPE;\n\n      default:\n        throw new InstrumentationException(\n            String.format(\"Invalid array opcode in getElementType: 0x%02X\", arrayOpcode));\n    }\n  }\n\n  public static String declarationToDescriptor(String decl) {\n    int leftParen = decl.indexOf('(');\n    int rightParen = decl.indexOf(')');\n    if (leftParen == -1 || rightParen == -1) {\n      throw new IllegalArgumentException();\n    }\n\n    StringBuilder buf = new StringBuilder();\n    String descriptor;\n\n    buf.append('(');\n    String args = decl.substring(leftParen + 1, rightParen);\n    StringTokenizer st = new StringTokenizer(args, \",\");\n    while (st.hasMoreTokens()) {\n      String arg = st.nextToken().trim();\n      descriptor = primitives.get(arg);\n      if (arg.length() == 0) {\n        throw new IllegalArgumentException();\n      }\n      if (descriptor == null) {\n        descriptor = objectOrArrayType(arg);\n      }\n      buf.append(descriptor);\n    }\n    buf.append(')');\n\n    String returnType = decl.substring(0, leftParen).trim();\n    descriptor = primitives.get(returnType);\n    if (returnType.length() == 0) {\n      throw new IllegalArgumentException();\n    }\n    if (descriptor == null) {\n      descriptor = objectOrArrayType(returnType);\n    }\n    buf.append(descriptor);\n    return buf.toString();\n  }\n\n  public static String descriptorToSimplified(String desc, String owner, String name) {\n    String retTypeDesc = null;\n    Type[] args = null;\n    if (desc.contains(\"(\")) {\n      retTypeDesc = Type.getReturnType(desc).getDescriptor();\n      args = Type.getArgumentTypes(desc);\n    } else {\n      retTypeDesc = isPrimitive(desc) ? desc : Type.getType(desc).getDescriptor();\n      args = new Type[0];\n    }\n    StringBuilder sb = new StringBuilder();\n    sb.append(getJavaType(retTypeDesc))\n        .append(' ')\n        .append(owner.replace('/', '.'))\n        .append('#')\n        .append(name);\n    if (args.length > 0) {\n      sb.append(\"(\");\n      boolean more = false;\n      for (Type t : args) {\n        if (more) {\n          sb.append(\", \");\n        } else {\n          more = true;\n        }\n        sb.append(getJavaType(t.getDescriptor()));\n      }\n      sb.append(')');\n    }\n    return sb.toString();\n  }\n\n  public static String getJavaType(String desc) {\n    int arrIndex = desc.lastIndexOf('[') + 1;\n    desc = arrIndex > 0 ? desc.substring(arrIndex) : desc;\n    if (desc.startsWith(\"L\")) {\n      desc = desc.substring(1, desc.length() - 1).replace('/', '.');\n    } else {\n      for (Map.Entry<String, String> entry : primitives.entrySet()) {\n        if (entry.getValue().equals(desc)) {\n          desc = entry.getKey();\n          break;\n        }\n      }\n    }\n    StringBuilder sb = new StringBuilder(desc);\n    for (int i = 0; i < arrIndex; i++) {\n      sb.append(\"[]\");\n    }\n    return sb.toString();\n  }\n\n  public static String objectOrArrayType(String type) {\n    StringBuilder buf = new StringBuilder();\n    int index = 0;\n    while ((index = type.indexOf(\"[]\", index) + 1) > 0) {\n      buf.append('[');\n    }\n    String t = type.substring(0, type.length() - buf.length() * 2);\n    String desc = primitives.get(t);\n    if (desc != null) {\n      buf.append(desc);\n    } else {\n      buf.append('L');\n      if (t.indexOf('.') < 0) {\n        buf.append(t);\n      } else {\n        buf.append(t.replace('.', '/'));\n      }\n      buf.append(';');\n    }\n    return buf.toString();\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/VariableMapper.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport org.objectweb.asm.Label;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class VariableMapper {\n  private static class CopyOnWriteArray {\n    private final int[] src;\n    private int[] copy = null;\n    private final int upperLimit;\n    CopyOnWriteArray(int[] src, int upperLimit) {\n      this.src = src;\n      this.upperLimit = upperLimit;\n    }\n\n    void force() {\n      copy = copy == null ? Arrays.copyOf(src, upperLimit) : copy;\n    }\n\n    int length() {\n      return copy == null ? upperLimit : copy.length;\n    }\n\n    void set(int pos, int value) {\n      if (copy == null) {\n        copy = Arrays.copyOf(src, Math.max(upperLimit, pos * 2));\n      } else if (pos >= copy.length) {\n        copy = Arrays.copyOf(copy, copy.length * 2);\n      }\n      copy[pos] = value;\n    }\n\n    int get(int pos) {\n      int[] target = copy != null ? copy : src;\n      if (pos >= target.length) {\n        throw new InstrumentationException(\n            String.format(\"Invalid variable index: %d (valid range: 0-%d)\", pos, target.length - 1));\n      }\n      return target[pos];\n    }\n  }\n\n  private static final int UNMASK = 0x1FFFFFFF;\n  static final int DOUBLE_SLOT_FLAG = 0x20000000;\n  static final int DOUBLE_SLOT_FLAG_2 = 0x40000000;\n  static final int REMAP_FLAG = 0x80000000;\n  private static final int INVALID_MASK = 0xFFFFFFFF;\n\n  private final int argsSize;\n\n  private int nextMappedVar = 0;\n  private int[] mapping;\n\n  private static final Label FIRST_LABEL = new Label();\n\n  private Label currentLabel = FIRST_LABEL;\n  private final Map<Label, CopyOnWriteArray> labelMappings = new HashMap<>(16);\n\n  public VariableMapper(int argsSize) {\n    this.argsSize = argsSize;\n    nextMappedVar = argsSize;\n    // Estimate: args + 8 locals + 16 instrumentation vars\n    this.mapping = new int[argsSize + 8 + 16];\n  }\n\n  VariableMapper(int argsSize, int nextMappedVar, int[] mapping) {\n    this.argsSize = argsSize;\n    this.nextMappedVar = nextMappedVar;\n    this.mapping = Arrays.copyOf(mapping, mapping.length);\n  }\n\n  public static int unmask(int var) {\n    return var & UNMASK;\n  }\n\n  public static boolean isInvalidMapping(int var) {\n    return (var & INVALID_MASK) != 0;\n  }\n\n  /**\n   * Creates a new scope for all the subsequent mappings.<br>\n   * Label snapshots capture the full mapping array capacity to handle variables\n   * that are declared but not yet remapped when the label is visited.\n   * @param label the scope label\n   */\n  public void noteLabel(Label label) {\n    labelMappings.put(currentLabel, new CopyOnWriteArray(mapping, mapping.length));\n    currentLabel = label;\n  }\n\n  void setMapping(int from, int to, int size) {\n    assert((to & REMAP_FLAG) != 0);\n\n    int padding = size == 1 ? 0 : 1;\n    if (mapping.length <= from + padding) {\n      mapping = Arrays.copyOf(mapping, Math.max(mapping.length * 2, from + padding + 1));\n    }\n    mapping[from] = to;\n    if (padding > 0) {\n      assert(((to & DOUBLE_SLOT_FLAG) != 0));\n      mapping[from + padding] = unmask(to) | REMAP_FLAG | DOUBLE_SLOT_FLAG_2; // padding\n    }\n  }\n\n  public int remap(int var, int size) {\n    if ((var & REMAP_FLAG) != 0) {\n      return unmask(var);\n    }\n\n    int offset = var - argsSize;\n    if (offset < 0) {\n      // self projection for method arguments\n      return var;\n    }\n    // materialize all copy-on-writes before we modify the backing array\n    labelMappings.forEach((k, v) -> v.force());\n    // ok, can continue with modifications\n    if (offset >= mapping.length) {\n      mapping = Arrays.copyOf(mapping, Math.max(mapping.length * 2, offset + 1));\n    }\n    int mappedVar = mapping[offset];\n    int unmasked = unmask(mappedVar);\n\n    boolean isRemapped = ((mappedVar & REMAP_FLAG) != 0);\n    if (size == 2) {\n      if ((mappedVar & DOUBLE_SLOT_FLAG) == 0) {\n        // no double slot mapping over an int slot;\n        // must re-map unless the int slot is the last used one or there is a free double-ext slot\n        isRemapped = false;\n      }\n    } else {\n      // size == 1\n      if ((mappedVar & DOUBLE_SLOT_FLAG_2) != 0) {\n        // no mapping over a previously 2-slot value\n        isRemapped = false;\n      } else if ((mappedVar & DOUBLE_SLOT_FLAG) != 0) {\n        // the previously second part of the double slot is free to reuse\n        mapping[offset + 1] = (unmasked + 1) | REMAP_FLAG;\n      }\n    }\n    if (!isRemapped) {\n      mappedVar = remapVar(newVarIdxInternal(size), size);\n      setMapping(offset, mappedVar, size);\n    }\n\n    unmasked = unmask(mappedVar);\n    // adjust the mapping pointer if remapping with variable occupying 2 slots\n    nextMappedVar = Math.max(unmasked + size, nextMappedVar);\n    return unmasked;\n  }\n\n  public int map(int var) {\n    return map(var, mapping);\n  }\n\n  public int map(int var, Label label) {\n    return map(var, labelMappings.getOrDefault(label, new CopyOnWriteArray(mapping, mapping.length)));\n  }\n\n  private int map(int var, CopyOnWriteArray currentMapping) {\n    // if the var number is the result of current mapping (REMAP_FLAG is set)\n    if (((var & REMAP_FLAG) != 0)) {\n      return unmask(var);\n    }\n\n    int offset = (var - argsSize);\n\n    // only remap locals slots above method arguments\n    if (offset >= 0) {\n      // If the snapshot is too small, fall back to the live mapping.\n      // This handles variables that were declared but not yet remapped when the snapshot was taken.\n      if (currentMapping.length() <= offset) {\n        // Check if variable exists in current live mapping\n        if (offset < mapping.length) {\n          int liveVar = mapping[offset];\n          if ((liveVar & REMAP_FLAG) != 0) {\n            return unmask(liveVar);\n          }\n        }\n        throw new InstrumentationException(\n            String.format(\n                \"Variable mapping out of bounds: var=%d, offset=%d, mappingSize=%d, argsSize=%d\",\n                var, offset, currentMapping.length(), argsSize));\n      }\n      int newVar = currentMapping.get(offset);\n      if ((newVar & REMAP_FLAG) == 0) {\n        throw new InstrumentationException(\n            String.format(\n                \"Variable not remapped: var=%d, offset=%d, mappedValue=0x%08X, argsSize=%d\",\n                var, offset, newVar, argsSize));\n      }\n      return unmask(newVar);\n    }\n    // method argument slots are not remapped\n    return var;\n  }\n\n  private int map(int var, int[] currentMapping) {\n    // if the var number is the result of current mapping (REMAP_FLAG is set)\n    if (((var & REMAP_FLAG) != 0)) {\n      return unmask(var);\n    }\n\n    int offset = (var - argsSize);\n\n    // only remap locals slots above method arguments\n    if (offset >= 0) {\n      if (currentMapping.length <= offset) {\n        throw new InstrumentationException(\n            String.format(\n                \"Variable mapping out of bounds: var=%d, offset=%d, mappingSize=%d, argsSize=%d\",\n                var, offset, currentMapping.length, argsSize));\n      }\n      int newVar = currentMapping[offset];\n      if ((newVar & REMAP_FLAG) == 0) {\n        throw new InstrumentationException(\n            String.format(\n                \"Variable not remapped: var=%d, offset=%d, mappedValue=0x%08X, argsSize=%d\",\n                var, offset, newVar, argsSize));\n      }\n      return unmask(newVar);\n    }\n    // method argument slots are not remapped\n    return var;\n  }\n\n  public int[] mappings() {\n    int[] cleansed = new int[mapping.length];\n    for (int i = 0; i < mapping.length; i++) {\n      cleansed[i] = unmask(mapping[i]);\n    }\n    return cleansed;\n  }\n\n  private int newVarIdxInternal(int size) {\n    int var = nextMappedVar;\n    nextMappedVar += size;\n    return var == 0 ? Integer.MIN_VALUE : var;\n  }\n\n  private int remapVar(int var, int size) {\n    int mappedVar = var | REMAP_FLAG;\n    if (size == 2) {\n      mappedVar = mappedVar | DOUBLE_SLOT_FLAG;\n    }\n    return mappedVar;\n  }\n\n  public int newVarIdx(int size) {\n    int var = newVarIdxInternal(size);\n    return remapVar(var, size);\n  }\n\n  public int getNextMappedVar() {\n    return nextMappedVar;\n  }\n\n  @Override\n  public String toString() {\n    StringBuilder sb = new StringBuilder(\"nextVar: \").append(nextMappedVar).append(\", mappings: [\");\n    for (int j : mapping) {\n      if ((j & REMAP_FLAG) != 0) {\n        sb.append(unmask(j));\n      } else {\n        sb.append(j);\n      }\n      sb.append(\",\");\n    }\n    sb.append(\"],\\n{\").append(Arrays.toString(mapping)).append(\"}\");\n    return sb.toString();\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/Verifier.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport static org.objectweb.asm.Opcodes.*;\n\nimport org.objectweb.asm.AnnotationVisitor;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.FieldVisitor;\nimport org.objectweb.asm.MethodVisitor;\nimport org.openjdk.btrace.core.Messages;\nimport org.openjdk.btrace.core.VerifierException;\nimport org.openjdk.btrace.core.extensions.Permission;\n\n/**\n * This class verifies that a BTrace program is safe and well-formed. Also it fills the onMethods\n * and onProbes structures with the data taken from the annotations\n *\n * @author A. Sundararajan\n * @author J. Bachorik\n */\npublic class Verifier extends ClassVisitor {\n  private final boolean trustedAllowed;\n  private final BTraceProbeNode cn;\n  private boolean seenBTrace;\n\n  public Verifier(BTraceProbeNode cv, boolean trusted) {\n    super(ASM9, cv);\n    trustedAllowed = trusted;\n    cn = cv;\n  }\n\n  public static void reportError(String err) {\n    reportError(err, null);\n  }\n\n  public static void reportError(String err, String msg) {\n    String str = Messages.get(err);\n    if (msg != null) {\n      str += \": \" + msg;\n    }\n    throw new VerifierException(str);\n  }\n\n  public String getClassName() {\n    return cn.name;\n  }\n\n  @Override\n  public void visitEnd() {\n    if (!trustedAllowed && !cn.isTrusted()) {\n      if (cn.getGraph().hasCycle()) {\n        reportSafetyError(\"execution.loop.danger\");\n      }\n    }\n    super.visitEnd();\n  }\n\n  @Override\n  public void visit(\n      int version,\n      int access,\n      String name,\n      String signature,\n      String superName,\n      String[] interfaces) {\n    if (!trustedAllowed && !cn.isTrusted()) {\n      if ((access & ACC_INTERFACE) != 0 || (access & ACC_ENUM) != 0) {\n        reportSafetyError(\"btrace.program.should.be.class\");\n      }\n      if ((access & ACC_PUBLIC) == 0) {\n        reportSafetyError(\"class.should.be.public\", name);\n      }\n\n      if (!superName.equals(Constants.OBJECT_INTERNAL)) {\n        reportSafetyError(\"object.superclass.required\", superName);\n      }\n      if (interfaces != null && interfaces.length > 0) {\n        reportSafetyError(\"no.interface.implementation\");\n      }\n    }\n    super.visit(version, access, name, signature, superName, interfaces);\n  }\n\n  @Override\n  public AnnotationVisitor visitAnnotation(String type, boolean visible) {\n    AnnotationVisitor delegate = super.visitAnnotation(type, visible);\n    if (type.equals(Constants.BTRACE_DESC)) {\n      seenBTrace = true;\n      return new AnnotationVisitor(ASM9, delegate) {\n        @Override\n        public void visit(String name, Object value) {\n          if ((\"unsafe\".equals(name) || \"trusted\".equals(name)) && Boolean.TRUE.equals(value)) {\n            if (!trustedAllowed) {\n              reportSafetyError(\"agent.unsafe.not.allowed\");\n            }\n            cn.setTrusted(); // Found @BTrace(..., trusted=true)\n          }\n          super.visit(name, value);\n        }\n      };\n    }\n    // RequestPermission annotations removed; ignore.\n    return delegate;\n  }\n\n  @Override\n  public FieldVisitor visitField(\n      int access, String name, String desc, String signature, Object value) {\n    if (!seenBTrace) {\n      reportSafetyError(\"not.a.btrace.program\");\n    }\n    if (!trustedAllowed && !cn.isTrusted()) {\n      if ((access & ACC_STATIC) == 0) {\n        reportSafetyError(\"agent.no.instance.variables\", name);\n      }\n    }\n    return super.visitField(access, name, desc, signature, value);\n  }\n\n  @Override\n  public void visitInnerClass(String name, String outerName, String innerName, int access) {\n    if (!trustedAllowed && !cn.isTrusted()) {\n      if (cn.name.equals(outerName)) {\n        reportSafetyError(\"no.nested.class\");\n      }\n    }\n  }\n\n  @Override\n  public MethodVisitor visitMethod(\n      int access, String methodName, String methodDesc, String signature, String[] exceptions) {\n\n    if (!seenBTrace) {\n      reportSafetyError(\"not.a.btrace.program\");\n    }\n\n    if (!trustedAllowed && !cn.isTrusted()) {\n      if ((access & ACC_SYNCHRONIZED) != 0) {\n        reportSafetyError(\"no.synchronized.methods\", methodName + methodDesc);\n      }\n\n      if (!methodName.equals(Constants.CONSTRUCTOR)) {\n        if ((access & ACC_STATIC) == 0) {\n          reportSafetyError(\"no.instance.method\", methodName + methodDesc);\n        }\n      }\n    }\n\n    return super.visitMethod(access, methodName, methodDesc, signature, exceptions);\n  }\n\n  @Override\n  public void visitOuterClass(String owner, String name, String desc) {\n    if (!trustedAllowed && !cn.isTrusted()) {\n      reportSafetyError(\"no.outer.class\");\n    }\n  }\n\n  void reportSafetyError(String err) {\n    reportSafetyError(err, null);\n  }\n\n  void reportSafetyError(String err, String msg) {\n    reportError(err, msg);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/random/SharedRandomIntProvider.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr.random;\n\nimport java.util.Random;\nimport org.openjdk.btrace.instr.RandomIntProvider;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic final class SharedRandomIntProvider extends RandomIntProvider {\n  private final Random rnd = new Random(System.nanoTime());\n\n  @Override\n  public int nextInt(int bound) {\n    return rnd.nextInt(bound);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/java/org/openjdk/btrace/instr/random/ThreadLocalRandomIntProvider.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr.random;\n\nimport java.util.concurrent.ThreadLocalRandom;\nimport org.openjdk.btrace.instr.RandomIntProvider;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic final class ThreadLocalRandomIntProvider extends RandomIntProvider {\n  @Override\n  public int nextInt(int bound) {\n    return ThreadLocalRandom.current().nextInt(0, bound);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/main/resources/META-INF/services/org.openjdk.btrace.compiler.PackGenerator",
    "content": "org.openjdk.btrace.instr.InstrPackGenerator\n"
  },
  {
    "path": "btrace-instr/src/main/resources/org/openjdk/btrace/instr/jaxb.index",
    "content": "ProbeDescriptor\nOnProbe\nOnMethod\nLocation"
  },
  {
    "path": "btrace-instr/src/test/btrace/ExportTest.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces;\n\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Export;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\nimport java.util.Deque;\n\n/**\n * Sanity test to make sure the @Export annotations work as expected.\n *\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class ExportTest {\n    @Export\n    public static final long z = 10L;\n    @Export\n    public static Deque<Long> entryTimes = BTraceUtils.Collections.newDeque();\n    @Export\n    public static String name;\n    @Export\n    public static int x = 10;\n    @Export\n    public static double y;\n\n    @OnMethod(clazz = \"resources.OnMethodTest\", method = \"args\")\n    public static void testArgs(String a, long b, String[] c, int[] d) {\n        BTraceUtils.push(entryTimes, b);\n        name = a;\n    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/InterestingVarsTest.java",
    "content": "package traces.issues;\n\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.BTraceUtils;\n\n@BTrace\nclass InterestingVarsTest {\n    @OnMethod(clazz = \"/.*\\\\.InterestingVarsClass/\", method = \"initAndStartApp\")\n    void entry(String a, String b, String c) {\n        BTraceUtils.println(a);\n    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/OnProbeTest.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnProbe;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class OnProbeTest {\n    @OnProbe(name = \"noargs\", namespace = \"org.openjdk.btrace\")\n    public static void noargs(@Self Object self) {\n        println(\"[this, noargs]\");\n    }\n\n    @OnProbe(name = \"withargs\", namespace = \"org.openjdk.btrace\")\n    public static void args(@Self Object self, int i, String s) {\n        dump(\"[this, args]\");\n    }\n\n    private static void dump(String s) {\n        println(s);\n    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/OnTimerTest.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnTimer;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class OnTimerTest {\n    static {\n        println(\"vm version \" + Sys.VM.vmVersion());\n        println(\"vm starttime \" + Sys.VM.vmStartTime());\n    }\n\n    @OnTimer(500)\n    public static void ontimer() {\n        dump(\"timer\");\n    }\n\n    private static void dump(String s) {\n        println(s);\n    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/TLSTest.java",
    "content": "/*\n * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces;\n\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.TLS;\n\nimport java.util.Deque;\n\n/**\n * Sanity test to make sure the @TLS annotations work as expected.\n *\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class TLSTest {\n    @TLS\n    public static final long z = 10L;\n    @TLS\n    public static Deque<Long> entryTimes = BTraceUtils.Collections.newDeque();\n    @TLS\n    public static String name;\n    @TLS\n    public static int x = 10;\n    @TLS\n    public static double y;\n\n    @OnMethod(clazz = \"resources.OnMethodTest\", method = \"args\")\n    public static void testArgs(String a, long b, String[] c, int[] d) {\n        BTraceUtils.push(entryTimes, b);\n        name = a;\n    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/TraceAllTest.java",
    "content": "/*\n * Copyright (c) 2024, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage traces;\n\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.BTraceUtils;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n *\n * @author Jaroslav Bachorik\n */\n@BTrace(trusted = false)\npublic class TraceAllTest {\n\n    private static final AtomicLong hitCnt = BTraceUtils.newAtomicLong(0);\n\n    @OnMethod(clazz = \"/.*/\")\n    public static void doall(@ProbeMethodName(fqn = true) String pmn) {\n        BTraceUtils.getAndIncrement(hitCnt);\n//        BTraceUtils.println(\"invoked: \" + pmn);\n    }\n\n    @OnTimer(500)\n    public static void doRecurrent() {\n        long cnt = BTraceUtils.get(hitCnt);\n        if (cnt > 0) {\n            println(\"[invocations=\" + cnt + \"]\");\n        }\n    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/issues/BTRACE106.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.issues;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\n\n@BTrace\npublic class BTRACE106 {\n  @OnMethod(clazz = \"@/.*\\\\.Deprecated/\", method = \"aMethod\")\n  public static void o1(@Self Object self, @ProbeMethodName String pmn) { // all calls to methods\n    println(pmn);\n  }\n\n  @OnMethod(clazz = \"@/.*\\\\.Deprecated/\", method = \"bMethod\", location = @Location(Kind.RETURN))\n  public static void o2(\n      @Self Object self, @ProbeMethodName String pmn, @Duration long dur) { // all calls to methods\n    println(pmn);\n  }\n\n  @OnMethod(\n      clazz = \"@/.*\\\\.Deprecated/\",\n      method = \"@/.*\\\\.Deprecated/\",\n      location = @Location(Kind.RETURN))\n  public static void o3(\n      @Self Object self, @ProbeMethodName String pmn, @Duration long dur) { // all calls to methods\n    println(pmn);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/issues/BTRACE189.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.issues;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\n\n@BTrace\npublic class BTRACE189 {\n  @OnMethod(clazz = \"@/.*/\", method = \"aMethod\")\n  public static void o1(@Self Object self, @ProbeMethodName String pmn) { // all calls to methods\n    sharedMethod(pmn);\n  }\n\n  private static void sharedMethod(String pmn) {\n    println(\"pmn = \" + pmn);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/issues/BTRACE22.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.issues;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class BTRACE22 {\n  @OnMethod(\n      clazz = \"/.*\\\\.BTRACE22/\",\n      method = \"testDouble\",\n      location = @Location(value = Kind.RETURN))\n  public static void tracker(@Self Object x, @Duration long dur) {\n    println(\"args empty\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/issues/BTRACE256.java",
    "content": "package traces.issues;\n\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.Profiler;\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.statsd.Statsd;\n\n@BTrace\nclass BTRACE256 {\n  @Property Profiler swingProfiler = BTraceUtils.Profiling.newProfiler();\n\n  @Injected\n  private Statsd sd;\n\n  @OnMethod(clazz = \"/.*\\\\.BTRACE256/\", method = \"doStuff\")\n  void entry(@ProbeMethodName(fqn = true) String probeMethod) {\n    BTraceUtils.Profiling.recordEntry(swingProfiler, probeMethod);\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.BTRACE256/\",\n      method = \"doStuff\",\n      location = @Location(value = Kind.RETURN))\n  void exit(@ProbeMethodName(fqn = true) String probeMethod, @Duration long duration) {\n    BTraceUtils.Profiling.recordExit(swingProfiler, probeMethod, duration);\n    sd.increment(\"my.metric.b\", \"regular,distribution:gaussian\");\n  }\n\n  @OnTimer(5000)\n  void timer() {\n    BTraceUtils.Profiling.printSnapshot(\"AM performance profile\", swingProfiler);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/issues/BTRACE28.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.issues;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class BTRACE28 {\n  @OnMethod(clazz = \"/.*\\\\.BTRACE28/\", method = \"/.*/\", location = @Location(value = Kind.RETURN))\n  public static void tracker(@ProbeClassName String pcn, @ProbeMethodName String pmn) {\n    println(pcn);\n    println(pmn);\n    println(\"args empty\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/issues/BTRACE53.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.issues;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class BTRACE53 {\n  @OnMethod(\n      clazz = \"/.*\\\\.DerivedClass/\",\n      method = \"<init>\",\n      location = @Location(value = Kind.RETURN))\n  public static void onInit(@Duration long dur) {\n    println(strcat(\"init: \", str(dur)));\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/issues/BTRACE69.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.issues;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\n\n/**\n * This script traces method/block entry into every method of every class in javax.swing package!\n * Think before using this script -- this will slow down your app significantly!! Note tha\n * Where.BEFORE is default. For synchronized blocks, BEFORE means before \"monitorenter\" bytecode.\n * For synchronized methods, we can not have probe point Where.BEFORE. Lock is acquired before\n * entering synchronized method. By making the probe point Where.AFTER for SYNC_ENTER, we probe\n * after monitorenter bytecode or synchronized method entry.\n */\n@BTrace\npublic class BTRACE69 {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"sync\",\n      location = @Location(value = Kind.SYNC_ENTRY, where = Where.AFTER))\n  public static void onSyncEntry(@TargetInstance Object obj) {\n    println(Strings.strcat(\"after synchronized entry: \", identityStr(obj)));\n  }\n\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"sync\", location = @Location(Kind.SYNC_EXIT))\n  public static void onSyncExit(@TargetInstance Object obj) {\n    println(Strings.strcat(\"before synchronized exit: \", identityStr(obj)));\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/issues/BTRACE87.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.issues;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/**\n * This script traces method/block entry into every method of every class in javax.swing package!\n * Think before using this script -- this will slow down your app significantly!! Note tha\n * Where.BEFORE is default. For synchronized blocks, BEFORE means before \"monitorenter\" bytecode.\n * For synchronized methods, we can not have probe point Where.BEFORE. Lock is acquired before\n * entering synchronized method. By making the probe point Where.AFTER for SYNC_ENTER, we probe\n * after monitorenter bytecode or synchronized method entry.\n */\n@BTrace\npublic class BTRACE87 {\n  @OnMethod(\n      clazz = \"/.*\\\\.BTRACE87/\",\n      method = \"/.*/\",\n      location = @Location(value = Kind.CALL, clazz = \"/.*/\", method = \"/.*/\"))\n  public static void o(\n      @Self Object self, @ProbeMethodName String pmn, AnyType[] args) { // all calls to methods\n    // self - this for the method call\n    // pmn - textual representation of the method\n    // contents of args array:\n    // [0]..[n] - original method call arguments\n    printArray(args);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/issues/BTRACE_333.java",
    "content": "package traces.issues;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\n\n@BTrace(unsafe = true)\npublic class BTRACE_333 {\n  @OnMethod(\n      clazz = \"com.bt.pjg.game.backpack.BackpackExtensionTest\",\n      method = \"/.*/\",\n      location = @Location(value = Kind.SYNC_ENTRY))\n  public static void m3() {\n    print(\"entered SYNC\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/issues/TezSplitter.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.issues;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.types.AnyType;\n\n@BTrace\npublic class TezSplitter {\n  @OnMethod(\n      clazz = \"org.apache.hadoop.mapred.split.TezMapredSplitsGrouper\",\n      method = \"getGroupedSplits\")\n  public static void getGroupedSplitsHook(AnyType[] args) {\n    println(\"here\");\n    //        Object[] vals = (Object[])(Object)args[1];\n    //        for (Object o : vals) {\n    //            println(o);\n    //        }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/AllLines.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class AllLines {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"<init>\",\n      location = @Location(value = Kind.LINE, line = -1))\n  public static void args(@Self Object self, @ProbeMethodName String pmn, int line) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/AnytypeArgs.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class AnytypeArgs {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  public static void args(@Self Object self, AnyType[] args) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/AnytypeArgsNoSelf.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class AnytypeArgsNoSelf {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  public static void argsNoSelf(AnyType[] args) {\n    println(\"args no self\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/Args.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TLS;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Args {\n  @TLS private static int cntr = 15;\n\n  @org.openjdk.btrace.core.annotations.Export private static long exported = 1;\n\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n    println(str(cntr));\n    cntr++;\n\n    println(str(exported));\n    exported++;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/Args2Sampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Args2Sampled {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args2(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsDuration.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDuration {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsDuration2.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDuration2 {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  public static void args2(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsDuration2Err.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDuration2Err {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.ERROR))\n  public static void args(@Self Object self, @Duration long dur, @TargetInstance Throwable err) {\n    println(\"args\");\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.ERROR))\n  public static void args2(@Self Object self, @Duration long dur, @TargetInstance Throwable err) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsDuration2Sampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDuration2Sampled {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args2(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsDurationBoxed.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationBoxed {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration Long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsDurationBoxedErr.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationBoxedErr {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.ERROR))\n  public static void args(@Self Object self, @Duration Long dur, Throwable err) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsDurationConstructor.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationConstructor {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"<init>\",\n      location = @Location(value = Kind.RETURN))\n  public static void args(@Self Object self, @Duration long dur, String a) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsDurationConstructorErr.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationConstructorErr {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"<init>\",\n      location = @Location(value = Kind.ERROR))\n  public static void args(@Self Object self, @Duration long dur, @TargetInstance Throwable err) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsDurationErr.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationErr {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.ERROR))\n  public static void args(@Self Object self, @Duration long dur, @TargetInstance Throwable err) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsDurationMultiReturn.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationMultiReturn {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"argsMultiReturn\",\n      location = @Location(value = Kind.RETURN))\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsDurationSampled.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationSampled {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  @Sampled(kind = Sampled.Sampler.Const, mean = 20)\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsNoSelf.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsNoSelf {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  public static void argsNoSelf(\n      @ProbeMethodName(fqn = true) String pmn, String a, long b, String[] c, int[] d) {\n    println(\"args no self\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsReturn.java",
    "content": "/*\n * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsReturn {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  public static void args(\n      @Self Object self, @Return long retVal, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsReturnAugmented.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace(unsafe = true)\npublic class ArgsReturnAugmented {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  public static long args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n    return 1;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsReturnAugmented1.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace(unsafe = true)\npublic class ArgsReturnAugmented1 {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  public static long args(\n      @Self Object self, @Return long ret, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n    return ret + 1;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsReturnBoxed.java",
    "content": "/*\n * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\nimport static org.openjdk.btrace.core.BTraceUtils.Reflective.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsReturnBoxed {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  public static void args(\n      @Self Object self, @Return AnyType retVal, String a, long b, String[] c, int[] d) {\n    println(\"args \" + getLong(\"value\", self));\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsReturnSampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsReturnSampled {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(\n      @Self Object self, @Return long retVal, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsReturnTypeMatch.java",
    "content": "/*\n * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsReturnTypeMatch {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      type = \"long (java.lang.String, long, java.lang.String[], int[])\",\n      location = @Location(value = Kind.RETURN))\n  public static void args(\n      @Self Object self, @Return long retVal, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsReturnTypeNoMatch.java",
    "content": "/*\n * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsReturnTypeNoMatch {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      type = \"int (java.lang.String, long, java.lang.String[], int[])\",\n      location = @Location(value = Kind.RETURN))\n  public static void args(\n      @Self Object self, @Return long retVal, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsReturnVoid.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsReturnVoid {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"noargs\",\n      location = @Location(value = Kind.RETURN))\n  public static void args(@Self Object self, @Return Void retVal) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsSampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsSampled {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsSampledAdaptive.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsSampledAdaptive {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  @Sampled(kind = Sampled.Sampler.Adaptive)\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsSampledNoSampling.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsSampledNoSampling {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  public static void argsNoSampling(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n  }\n\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void argsSampled(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsShared.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TLS;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsShared {\n  @TLS private static int cntr = 15;\n\n  @org.openjdk.btrace.core.annotations.Export private static long exported = 1;\n\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n    println(str(cntr));\n    cntr++;\n\n    dumpExported();\n  }\n\n  private static void dumpExported() {\n    println(str(exported));\n    incExported();\n  }\n\n  private static void incExported() {\n    exported++;\n  }\n\n  private static void unusedcode() {\n    println(\"unused\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsSigMatch.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsSigMatch {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"argsTypeMatch\")\n  public static void m1(@Self Object self, List<String> a) {\n    println(\"m1\");\n  }\n\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"argsTypeMatch\", exactTypeMatch = true)\n  public static void m2(@Self AnyType self, List<String> a) {\n    println(\"m2\");\n  }\n\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"argsTypeMatch\", exactTypeMatch = true)\n  public static void m3(@Self AnyType self, ArrayList<String> a) {\n    println(\"m3\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArgsUnsafe.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace(unsafe = true)\npublic class ArgsUnsafe {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    try {\n      double la = Sys.VM.systemLoadAverage();\n      long t = Sys.VM.processCPUTime();\n      println(la + \" # \" + t);\n    } catch (Throwable e) {\n      println(\"FAILED\");\n      println(e.getMessage());\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArrayGetAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArrayGetAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_GET, where = Where.AFTER))\n  public static void args(\n      @Self Object self, @Return int retVal, @TargetInstance int[] target, int index) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArrayGetAfterAny.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArrayGetAfterAny {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_GET, where = Where.AFTER))\n  public static void args(\n      @Self Object self, @Return AnyType retVal, @TargetInstance AnyType target, int index) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArrayGetBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArrayGetBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_GET))\n  public static void args(@Self Object self, @TargetInstance int[] arr, int index) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArrayGetBeforeAny.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArrayGetBeforeAny {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_GET))\n  public static void args(@Self Object self, @TargetInstance AnyType arr, int index) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArraySetAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArraySetAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_SET, where = Where.AFTER))\n  public static void args(@Self Object self, @TargetInstance int[] arr, int index, int value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArraySetAfterAny.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArraySetAfterAny {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_SET, where = Where.AFTER))\n  public static void args(\n      @Self Object self, @TargetInstance AnyType arr, int index, AnyType value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArraySetBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArraySetBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_SET))\n  public static void args(@Self Object self, @TargetInstance int[] arr, int index, int value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ArraySetBeforeAny.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArraySetBeforeAny {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_SET))\n  public static void args(\n      @Self Object self, @TargetInstance AnyType arr, int index, AnyType value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/Catch.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport java.io.IOException;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Catch {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"exception\",\n      location = @Location(value = Kind.CATCH))\n  public static void args(@Self Object self, @TargetInstance IOException e) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/CheckcastAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class CheckcastAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"casts\",\n      location = @Location(value = Kind.CHECKCAST, where = Where.AFTER))\n  public static void args(\n      @Self Object self,\n      @ProbeMethodName String pmn,\n      @TargetInstance AnyType target,\n      String castTo) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/CheckcastBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class CheckcastBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"casts\",\n      location = @Location(value = Kind.CHECKCAST))\n  public static void args(\n      @Self Object self,\n      @ProbeClassName String pcn,\n      String castTo,\n      @TargetInstance AnyType target) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ConstructorArgs.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ConstructorArgs {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"<init>\")\n  public static void args(@Self Object self, String a) {\n    println(\"constructor args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/Error.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Error {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"uncaught\",\n      location = @Location(value = Kind.ERROR))\n  public static void args(\n      @Self Object self, @ProbeMethodName String pmn, @TargetInstance Throwable cause) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ErrorCaught.java",
    "content": "/*\n * Copyright (c) 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ErrorCaught {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"caught\",\n      location = @Location(value = Kind.ERROR))\n  public static void args(\n      @Self Object self, @ProbeMethodName String pmn, @TargetInstance Throwable cause) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ErrorDuration.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ErrorDuration {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"uncaught\",\n      location = @Location(value = Kind.ERROR))\n  public static void args(\n      @Self Object self,\n      @ProbeMethodName String pmn,\n      @Duration long dur,\n      @TargetInstance Throwable cause) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/FieldGetAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldGetAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"field\",\n      location =\n          @Location(\n              value = Kind.FIELD_GET,\n              clazz = \"/^resources.OnMethodTest$/\",\n              field = \"/^field$/\",\n              where = Where.AFTER))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField(fqn = true) String fldName,\n      @Return int fldVal) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/FieldGetAfterStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldGetAfterStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"staticField\",\n      location =\n          @Location(\n              value = Kind.FIELD_GET,\n              clazz = \"/^resources.OnMethodTest$/\",\n              field = \"/^sField$/\",\n              where = Where.AFTER))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField(fqn = true) String fldName,\n      @Return long fldVal) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/FieldGetBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldGetBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"field\",\n      location = @Location(value = Kind.FIELD_GET, clazz = \"/.*\\\\.OnMethodTest/\", field = \"/^field$/\"))\n  public static void args(\n      @Self Object self, @TargetInstance Object inst, @TargetMethodOrField String fldName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/FieldGetBeforeStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldGetBeforeStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"staticField\",\n      location = @Location(value = Kind.FIELD_GET, clazz = \"/.*\\\\.OnMethodTest/\", field = \"/^sField$/\"))\n  public static void args(\n      @Self Object self, @TargetInstance Object inst, @TargetMethodOrField String fldName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/FieldSetAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldSetAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"field\",\n      location =\n          @Location(\n              value = Kind.FIELD_SET,\n              clazz = \"resources.OnMethodTest\",\n              field = \"/^field$/\",\n              where = Where.AFTER))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField String fldName,\n      int value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/FieldSetAfterStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldSetAfterStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"staticField\",\n      location =\n          @Location(\n              value = Kind.FIELD_SET,\n              clazz = \"resources.OnMethodTest\",\n              field = \"/^sField$/\",\n              where = Where.AFTER))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField String fldName,\n      long value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/FieldSetBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldSetBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"field\",\n      location = @Location(value = Kind.FIELD_SET, clazz = \"/.*\\\\.OnMethodTest/\", field = \"/^field$/\"))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField String fldName,\n      int value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/FieldSetBeforeStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldSetBeforeStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"staticField\",\n      location = @Location(value = Kind.FIELD_SET, clazz = \"/.*\\\\.OnMethodTest/\", field = \"/^sField$/\"))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField String fldName,\n      long value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/InstanceofAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class InstanceofAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"casts\",\n      location = @Location(value = Kind.INSTANCEOF, where = Where.AFTER))\n  public static void args(\n      @Self Object self, @ProbeMethodName String pmn, String type, @TargetInstance AnyType target) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/InstanceofBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class InstanceofBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"casts\",\n      location = @Location(value = Kind.INSTANCEOF))\n  public static void args(\n      @Self Object self, @ProbeClassName String pcn, String type, @TargetInstance AnyType target) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/Line.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Line {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"field\",\n      location = @Location(value = Kind.LINE, line = 84))\n  public static void args(@Self Object self, @ProbeMethodName String pmn, int line) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MatchAnnotated.java",
    "content": "/*\n * Copyright (c) 2017, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MatchAnnotated {\n  @OnMethod(\n      clazz = \"@org.openjdk.btrace.core.annotations.BTrace\",\n      method = \"@org.openjdk.btrace.core.annotations.Level\")\n  public static void args(@Self AnyType self) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MatchAnnotatedRegex.java",
    "content": "/*\n * Copyright (c) 2017, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MatchAnnotatedRegex {\n  @OnMethod(\n      clazz = \"@/.*\\\\.BTrace/\",\n      method = \"@/org\\\\.openjdk\\\\.btrace\\\\.core\\\\.annotations\\\\..*/\")\n  public static void args(@Self AnyType self) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MatchDerived.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport java.util.Map;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport resources.AbstractClass;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MatchDerived {\n  @OnMethod(clazz = \"+resources.AbstractClass\", method = \"/do(Get|Set)/\")\n  public static void args(@Self AbstractClass self, String a, Map b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCall.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCall {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location = @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTarget\"))\n  public static void args(\n      @Self Object self,\n      String a,\n      long b,\n      @TargetInstance Object calledSelf,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCallDuration.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallDuration {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER))\n  public static void args(@Return long retVal, @Duration long dur, String a, long b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCallDuration2.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallDuration2 {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER))\n  public static void args0(@Return long retVal, @Duration long dur, String a, long b) {\n    println(\"args\");\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER))\n  public static void args1(@Return long retVal, @Duration long dur, String a, long b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCallDurationSampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallDurationSampled {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(@Return long retVal, @Duration long dur, String a, long b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCallDurationSampledMulti.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallDurationSampledMulti {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel1\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"/callTarget.*/\",\n              where = Where.AFTER))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(@Return long retVal, @Duration long dur, String a, long b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCallNoArgs.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallNoArgs {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location = @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTarget\"))\n  public static void args() {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCallReturn.java",
    "content": "/*\n * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallReturn {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER))\n  public static void args(@Return long retVal, String a, long b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCallReturnAugmented.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace(unsafe = true)\npublic class MethodCallReturnAugmented {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER))\n  public static long args(String a, long b) {\n    println(\"args\");\n    return 1;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCallReturnAugmented1.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace(unsafe = true)\npublic class MethodCallReturnAugmented1 {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER))\n  public static long args(@Return long retVal, String a, long b) {\n    println(\"args\");\n    return retVal + 1;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCallSampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallSampled {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location = @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTarget\"))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(\n      @Self Object self,\n      String a,\n      long b,\n      @TargetInstance Object calledSelf,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCallSampledAdaptive.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallSampledAdaptive {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location = @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTarget\"))\n  @Sampled(kind = Sampled.Sampler.Adaptive)\n  public static void args(\n      @Self Object self,\n      String a,\n      long b,\n      @TargetInstance Object calledSelf,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/MethodCallStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTargetStatic\"))\n  public static void args(\n      @Self Object self,\n      String a,\n      long b,\n      @TargetInstance Object target,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/NativeWithReturn.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NativeWithReturn {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"nativeWithReturn\")\n  public static void nMethod(@Self Object self) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/NativeWithoutReturn.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NativeWithoutReturn {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"nativeWithoutReturn\")\n  public static void nMethod(@Self Object self) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/NewAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport java.util.Map;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newObject\",\n      location = @Location(value = Kind.NEW, clazz = \"/.*/\", where = Where.AFTER))\n  public static void args(@Self Object self, @Return Map instance, String instanceClassName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/NewArrayIntAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewArrayIntAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newArray\",\n      location = @Location(value = Kind.NEWARRAY, clazz = \"int\", where = Where.AFTER))\n  public static void args(@Self Object self, @Return int[] retVal) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/NewArrayIntBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewArrayIntBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newArray\",\n      location = @Location(value = Kind.NEWARRAY, clazz = \"int\"))\n  public static void args(@Self Object self, String arrayType, int dims) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/NewArrayStringAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewArrayStringAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newArray\",\n      location =\n          @Location(value = Kind.NEWARRAY, clazz = \"/java\\\\.lang\\\\.String.*/\", where = Where.AFTER))\n  public static void args(@Self Object self, @Return String[] retVal) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/NewArrayStringBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewArrayStringBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newArray\",\n      location = @Location(value = Kind.NEWARRAY, clazz = \"/java\\\\.lang\\\\.String.*/\"))\n  public static void args(@Self Object self, String arrayType, int dims) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/NewBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newObject\",\n      location = @Location(value = Kind.NEW, clazz = \"/.*/\"))\n  public static void args(@Self Object self, String instanceClassName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/NoArgs.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NoArgs {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  public static void argsEmpty(@Self Object x) {\n    println(\"args empty\");\n  }\n\n  //    @OnMethod(clazz=\"/.*\\\\.OnMethodTest/\", method=\"args\")\n  //    public static void argsNoSelf(String a, int b, String[] c, int[] d) {\n  //        println(\"args no self\");\n  //    }\n  //\n  //    @OnMethod(clazz=\"/.*/\", method=\"args\")\n  //    public static void args(@Self Object self, String a, int b, String[] c, int[] d) {\n  //        println(\"args\");\n  //    }\n  //\n  //    @OnMethod(clazz=\"/.*/\", method=\"args$static\")\n  //    public static void staticArgs() {\n  //        println(\"args$static\");\n  //    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/NoArgsEntryReturn.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NoArgsEntryReturn {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  public static void argsEmptyEntry(@Self Object x) {\n    println(\"entry\");\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  public static void argsEmptyReturn(@Self Object x, @Return long ret) {\n    println(\"return\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/NoArgsEntryReturnNoCapture.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NoArgsEntryReturnNoCapture {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\")\n  public static void argsEmptyEntry(@Self Object x) {\n    println(\"entry\");\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN))\n  public static void argsEmptyReturn(@Self Object x) {\n    println(\"return\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/ServicesTest.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Injected;\nimport org.openjdk.btrace.core.annotations.InjectionMode;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.utils.PrinterService;\nimport org.openjdk.btrace.statsd.Statsd;\n\n@BTrace\npublic class ServicesTest {\n  @Injected\n  private static PrinterService printer;\n\n  @Injected\n  private static Statsd statsd;\n\n  @OnMethod(clazz = \"resources.OnMethodTest\", method = \"noargs$static\")\n  public static void testFieldInjection(@ProbeClassName String pcn) {\n    printer.println(\"svc-injection ok: \" + pcn);\n    statsd.increment(\"btrace.services.test\", \"source:onmethod\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/StaticArgs.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticArgs {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args$static\")\n  public static void args(String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/StaticArgsReturn.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticArgsReturn {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args$static\",\n      location = @Location(value = Kind.RETURN))\n  public static void args(String a, @Return long retVal, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/StaticArgsSelf.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticArgsSelf {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args$static\")\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/StaticMethodCall.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticMethodCall {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevelStatic\",\n      location = @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTarget\"))\n  public static void args(\n      String a,\n      long b,\n      @TargetInstance Object calledSelf,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/StaticMethodCallStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticMethodCallStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevelStatic\",\n      location =\n          @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTargetStatic\"))\n  public static void args(\n      String a,\n      long b,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/StaticNoArgs.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticNoArgs {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"noargs$static\")\n  public static void argsEmpty() {\n    println(\"args empty\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/StaticNoArgsSelf.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticNoArgsSelf {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"noargs$static\")\n  public static void argsEmpty(@Self Object self) {\n    println(\"args empty\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/SyncEntry.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class SyncEntry {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"sync\",\n      location = @Location(value = Kind.SYNC_ENTRY))\n  public static void args(\n      @Self Object self, @ProbeMethodName String pmn, @TargetInstance Object lock) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/SyncExit.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class SyncExit {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"sync\",\n      location = @Location(value = Kind.SYNC_EXIT))\n  public static void args(\n      @Self Object self, @ProbeClassName String pcn, @TargetInstance Object lock) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/SyncMEntry.java",
    "content": "/*\n * Copyright (c) 2017, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class SyncMEntry {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"syncM\",\n      location = @Location(value = Kind.SYNC_ENTRY))\n  public static void args(\n      @Self Object self, @ProbeMethodName String pmn, @TargetInstance Object lock) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/SyncMExit.java",
    "content": "/*\n * Copyright (c) 2017, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class SyncMExit {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"syncM\",\n      location = @Location(value = Kind.SYNC_EXIT))\n  public static void args(\n      @Self Object self, @ProbeClassName String pcn, @TargetInstance Object lock) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/Throw.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Throw {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"exception\",\n      location = @Location(value = Kind.THROW))\n  public static void args(\n      @Self Object self,\n      @ProbeClassName String pcn,\n      @ProbeMethodName String pmn,\n      @TargetInstance Throwable e) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/AnytypeArgs.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class AnytypeArgs {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, AnyType[] args) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/AnytypeArgsNoSelf.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class AnytypeArgsNoSelf {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  public static void argsNoSelf(AnyType[] args) {\n    println(\"args no self\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/Args.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TLS;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Args {\n  @TLS private static int cntr = 15;\n\n  @org.openjdk.btrace.core.annotations.Export private static long exported = 1;\n\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n    println(str(cntr));\n    cntr++;\n\n    println(str(exported));\n    exported++;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/Args2Sampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Args2Sampled {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args2(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsDuration.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDuration {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsDuration2.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDuration2 {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  public static void args2(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsDuration2Err.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDuration2Err {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.ERROR),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @Duration long dur, @TargetInstance Throwable err) {\n    println(\"args\");\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.ERROR),\n      enableAt = @Level(\">=1\"))\n  public static void args2(@Self Object self, @Duration long dur, @TargetInstance Throwable err) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsDuration2Sampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDuration2Sampled {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\"<=5\"))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args2(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsDurationBoxed.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationBoxed {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration Long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsDurationBoxedErr.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationBoxedErr {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.ERROR),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @Duration Long dur, Throwable err) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsDurationConstructor.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationConstructor {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"<init>\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @Duration long dur, String a) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsDurationConstructorErr.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationConstructorErr {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"<init>\",\n      location = @Location(value = Kind.ERROR),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @Duration long dur, @TargetInstance Throwable err) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsDurationErr.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationErr {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.ERROR),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @Duration long dur, @TargetInstance Throwable err) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsDurationMultiReturn.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationMultiReturn {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"argsMultiReturn\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsDurationSampled.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsDurationSampled {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Const, mean = 20)\n  public static void args(\n      @Self Object self,\n      @Return long retVal,\n      @Duration long dur,\n      String a,\n      long b,\n      String[] c,\n      int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsNoSelf.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsNoSelf {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  public static void argsNoSelf(\n      @ProbeMethodName(fqn = true) String pmn, String a, long b, String[] c, int[] d) {\n    println(\"args no self\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsReturn.java",
    "content": "/*\n * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsReturn {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @Return long retVal, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsReturnAugmented.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace(unsafe = true)\npublic class ArgsReturnAugmented {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  public static long args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n    return 1;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsReturnAugmented1.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace(unsafe = true)\npublic class ArgsReturnAugmented1 {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  public static long args(\n      @Self Object self, @Return long ret, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n    return ret + 1;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsReturnSampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsReturnSampled {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(\n      @Self Object self, @Return long retVal, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsSampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsSampled {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsSampledAdaptive.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsSampledAdaptive {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Adaptive)\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsSampledNoSampling.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsSampledNoSampling {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  public static void argsNoSampling(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n  }\n\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void argsSampled(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsShared.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TLS;\nimport traces.onmethod.*;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArgsShared {\n  @TLS private static int cntr = 15;\n\n  @org.openjdk.btrace.core.annotations.Export private static long exported = 1;\n\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"this = \" + self);\n    println(\"args\");\n    println(str(cntr));\n    cntr++;\n\n    dumpExported();\n  }\n\n  private static void dumpExported() {\n    println(str(exported));\n    incExported();\n  }\n\n  private static void incExported() {\n    exported++;\n  }\n\n  private static void unusedcode() {\n    println(\"unused\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArgsUnsafe.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace(unsafe = true)\npublic class ArgsUnsafe {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    try {\n      double la = Sys.VM.systemLoadAverage();\n      long t = Sys.VM.processCPUTime();\n      println(la + \" # \" + t);\n    } catch (Throwable e) {\n      println(\"FAILED\");\n      println(e.getMessage());\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArrayGetAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArrayGetAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_GET, where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @Return int retVal, @TargetInstance int[] arr, int index) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArrayGetAfterAny.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.core.types.AnyType;\nimport traces.onmethod.*;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArrayGetAfterAny {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_GET, where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @Return AnyType retVal, @TargetInstance AnyType target, int index) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArrayGetBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArrayGetBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_GET),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @TargetInstance int[] arr, int index) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArrayGetBeforeAny.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.types.AnyType;\nimport traces.onmethod.*;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArrayGetBeforeAny {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_GET),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @TargetInstance AnyType arr, int index) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArraySetAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArraySetAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_SET, where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @TargetInstance int[] arr, int index, int value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArraySetAfterAny.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.core.types.AnyType;\nimport traces.onmethod.*;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArraySetAfterAny {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_SET, where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @TargetInstance AnyType arr, int index, AnyType value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArraySetBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArraySetBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_SET),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @TargetInstance int[] arr, int index, int value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ArraySetBeforeAny.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.types.AnyType;\nimport traces.onmethod.*;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ArraySetBeforeAny {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"array\",\n      location = @Location(value = Kind.ARRAY_SET),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @TargetInstance AnyType arr, int index, AnyType value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/Catch.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport java.io.IOException;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Catch {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"exception\",\n      location = @Location(value = Kind.CATCH),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @TargetInstance IOException e) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/CheckcastAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class CheckcastAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"casts\",\n      location = @Location(value = Kind.CHECKCAST, where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @ProbeMethodName String pmn,\n      String castTo,\n      @TargetInstance AnyType target) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/CheckcastBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class CheckcastBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"casts\",\n      location = @Location(value = Kind.CHECKCAST),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @ProbeClassName String pcn,\n      String castTo,\n      @TargetInstance AnyType target) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ConstructorArgs.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ConstructorArgs {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"<init>\", enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, String a) {\n    println(\"constructor args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/Error.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Error {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"uncaught\",\n      location = @Location(value = Kind.ERROR),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @ProbeMethodName String pmn, @TargetInstance Throwable cause) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ErrorCaught.java",
    "content": "/*\n * Copyright (c) 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ErrorCaught {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"caught\",\n      location = @Location(value = Kind.ERROR),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @ProbeMethodName String pmn, @TargetInstance Throwable cause) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/ErrorDuration.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class ErrorDuration {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"uncaught\",\n      location = @Location(value = Kind.ERROR),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @ProbeMethodName String pmn,\n      @Duration long dur,\n      @TargetInstance Throwable cause) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/FieldGetAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldGetAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"field\",\n      location =\n          @Location(\n              value = Kind.FIELD_GET,\n              clazz = \"/^resources.OnMethodTest$/\",\n              field = \"/^field$/\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField(fqn = true) String fldName,\n      @Return int fldVal) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/FieldGetAfterStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldGetAfterStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"staticField\",\n      location =\n          @Location(\n              value = Kind.FIELD_GET,\n              clazz = \"/^resources.OnMethodTest$/\",\n              field = \"/^sField$/\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField(fqn = true) String fldName,\n      @Return long fldVal) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/FieldGetBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldGetBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"field\",\n      location = @Location(value = Kind.FIELD_GET, clazz = \"/.*\\\\.OnMethodTest/\", field = \"/^field$/\"),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @TargetInstance Object inst, @TargetMethodOrField String fldName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/FieldGetBeforeStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldGetBeforeStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"staticField\",\n      location = @Location(value = Kind.FIELD_GET, clazz = \"/.*\\\\.OnMethodTest/\", field = \"/^sField$/\"),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @TargetInstance Object inst, @TargetMethodOrField String fldName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/FieldSetAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldSetAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"field\",\n      location =\n          @Location(\n              value = Kind.FIELD_SET,\n              clazz = \"resources.OnMethodTest\",\n              field = \"/^field$/\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField String fldName,\n      int value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/FieldSetAfterStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldSetAfterStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"staticField\",\n      location =\n          @Location(\n              value = Kind.FIELD_SET,\n              clazz = \"resources.OnMethodTest\",\n              field = \"/^sField$/\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField String fldName,\n      long value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/FieldSetBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldSetBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"field\",\n      location = @Location(value = Kind.FIELD_SET, clazz = \"/.*\\\\.OnMethodTest/\", field = \"/^field$/\"),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField String fldName,\n      int value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/FieldSetBeforeStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class FieldSetBeforeStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"staticField\",\n      location = @Location(value = Kind.FIELD_SET, clazz = \"/.*\\\\.OnMethodTest/\", field = \"/^sField$/\"),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @TargetInstance Object inst,\n      @TargetMethodOrField String fldName,\n      long value) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/InstanceofAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.Where;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class InstanceofAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"casts\",\n      location = @Location(value = Kind.INSTANCEOF, where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @ProbeMethodName String pmn, String type, @TargetInstance AnyType target) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/InstanceofBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.types.AnyType;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class InstanceofBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"casts\",\n      location = @Location(value = Kind.INSTANCEOF),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @ProbeClassName String pcn, String type, @TargetInstance AnyType target) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/Line.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Line {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"field\",\n      location = @Location(value = Kind.LINE, line = 84),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @ProbeMethodName String pmn, int line) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MatchDerived.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport java.util.Map;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\nimport resources.AbstractClass;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MatchDerived {\n  @OnMethod(clazz = \"+resources.AbstractClass\", method = \"/do(Get|Set)/\", enableAt = @Level(\">=1\"))\n  public static void args(@Self AbstractClass self, String a, Map b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCall.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCall {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location = @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTarget\"),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      String a,\n      long b,\n      @TargetInstance Object calledSelf,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCallDuration.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallDuration {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Return long retVal, @Duration long dur, String a, long b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCallDuration2.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallDuration2 {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args0(@Return long retVal, @Duration long dur, String a, long b) {\n    println(\"args\");\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args1(@Return long retVal, @Duration long dur, String a, long b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCallDurationSampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallDurationSampled {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(@Return long retVal, @Duration long dur, String a, long b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCallDurationSampledMulti.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallDurationSampledMulti {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel1\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"/callTarget.*/\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(@Return long retVal, @Duration long dur, String a, long b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCallNoArgs.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallNoArgs {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location = @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTarget\"),\n      enableAt = @Level(\">=1\"))\n  public static void args() {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCallReturn.java",
    "content": "/*\n * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallReturn {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Return long retVal, String a, long b) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCallReturnAugmented.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace(unsafe = true)\npublic class MethodCallReturnAugmented {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static long args(String a, long b) {\n    println(\"args\");\n    return 1;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCallReturnAugmented1.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace(unsafe = true)\npublic class MethodCallReturnAugmented1 {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(\n              value = Kind.CALL,\n              clazz = \"/.*\\\\.OnMethodTest/\",\n              method = \"callTarget\",\n              where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static long args(@Return long retVal, String a, long b) {\n    println(\"args\");\n    return retVal + 1;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCallSampled.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallSampled {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location = @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTarget\"),\n      enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Const)\n  public static void args(\n      @Self Object self,\n      String a,\n      long b,\n      @TargetInstance Object calledSelf,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCallSampledAdaptive.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Sampled;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallSampledAdaptive {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location = @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTarget\"),\n      enableAt = @Level(\">=1\"))\n  @Sampled(kind = Sampled.Sampler.Adaptive)\n  public static void args(\n      @Self Object self,\n      String a,\n      long b,\n      @TargetInstance Object calledSelf,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/MethodCallStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class MethodCallStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevel\",\n      location =\n          @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTargetStatic\"),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      String a,\n      long b,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/NativeWithReturn.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NativeWithReturn {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"nativeWithReturn\", enableAt = @Level(\">=1\"))\n  public static void nMethod(@Self Object self) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/NativeWithoutReturn.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NativeWithoutReturn {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"nativeWithoutReturn\", enableAt = @Level(\">=1\"))\n  public static void nMethod(@Self Object self) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/NewAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport java.util.Map;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newObject\",\n      location = @Location(value = Kind.NEW, clazz = \"/.*/\", where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @Return Map instance, String instanceClassName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/NewArrayIntAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewArrayIntAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newArray\",\n      location = @Location(value = Kind.NEWARRAY, clazz = \"int\", where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @Return int[] retVal) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/NewArrayIntBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewArrayIntBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newArray\",\n      location = @Location(value = Kind.NEWARRAY, clazz = \"int\"),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, String arrayType, int dims) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/NewArrayStringAfter.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.Where;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewArrayStringAfter {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newArray\",\n      location = @Location(value = Kind.NEWARRAY, clazz = \"java.lang.String\", where = Where.AFTER),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, @Return String[] retVal) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/NewArrayStringBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewArrayStringBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newArray\",\n      location = @Location(value = Kind.NEWARRAY, clazz = \"java.lang.String\"),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, String arrayType, int dims) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/NewBefore.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NewBefore {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"newObject\",\n      location = @Location(value = Kind.NEW, clazz = \"/.*/\"),\n      enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, String instanceClassName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/NoArgs.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NoArgs {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  public static void argsEmpty(@Self Object x) {\n    println(\"args empty\");\n  }\n\n  //    @OnMethod(clazz=\"/.*\\\\.OnMethodTest/\", method=\"args\", level  = 1)\n  //    public static void argsNoSelf(String a, int b, String[] c, int[] d) {\n  //        println(\"args no self\");\n  //    }\n  //\n  //    @OnMethod(clazz=\"/.*/\", method=\"args\", level  = 1)\n  //    public static void args(@Self Object self, String a, int b, String[] c, int[] d) {\n  //        println(\"args\");\n  //    }\n  //\n  //    @OnMethod(clazz=\"/.*/\", method=\"args$static\", level  = 1)\n  //    public static void staticArgs() {\n  //        println(\"args$static\");\n  //    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/NoArgsEntryReturn.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class NoArgsEntryReturn {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args\", enableAt = @Level(\">=1\"))\n  public static void argsEmptyEntry(@Self Object x) {\n    println(\"entry\");\n  }\n\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  public static void argsEmptyReturn(@Self Object x) {\n    println(\"return\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/StaticArgs.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticArgs {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args$static\", enableAt = @Level(\">=1\"))\n  public static void args(String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/StaticArgsReturn.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Return;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticArgsReturn {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"args$static\",\n      location = @Location(value = Kind.RETURN),\n      enableAt = @Level(\">=1\"))\n  public static void args(String a, @Return long retVal, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/StaticArgsSelf.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticArgsSelf {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"args$static\", enableAt = @Level(\">=1\"))\n  public static void args(@Self Object self, String a, long b, String[] c, int[] d) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/StaticMethodCall.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticMethodCall {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevelStatic\",\n      location = @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTarget\"),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      String a,\n      long b,\n      @TargetInstance Object calledSelf,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/StaticMethodCallStatic.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.TargetMethodOrField;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticMethodCallStatic {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"callTopLevelStatic\",\n      location =\n          @Location(value = Kind.CALL, clazz = \"/.*\\\\.OnMethodTest/\", method = \"callTargetStatic\"),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      String a,\n      long b,\n      @TargetMethodOrField(fqn = true) String calledMethod,\n      @ProbeClassName String className,\n      @ProbeMethodName String methodName) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/StaticNoArgs.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticNoArgs {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"noargs$static\", enableAt = @Level(\">=1\"))\n  public static void argsEmpty() {\n    println(\"args empty\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/StaticNoArgsSelf.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class StaticNoArgsSelf {\n  @OnMethod(clazz = \"/.*\\\\.OnMethodTest/\", method = \"noargs$static\", enableAt = @Level(\">=1\"))\n  public static void argsEmpty(@Self Object self) {\n    println(\"args empty\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/SyncEntry.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class SyncEntry {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"sync\",\n      location = @Location(value = Kind.SYNC_ENTRY),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @ProbeMethodName String pmn, @TargetInstance Object lock) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/SyncExit.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class SyncExit {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"sync\",\n      location = @Location(value = Kind.SYNC_EXIT),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @ProbeClassName String pcn, @TargetInstance Object lock) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/SyncMEntry.java",
    "content": "/*\n * Copyright (c) 2017, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class SyncMEntry {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"syncM\",\n      location = @Location(value = Kind.SYNC_ENTRY),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @ProbeMethodName String pmn, @TargetInstance Object lock) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/SyncMExit.java",
    "content": "/*\n * Copyright (c) 2017, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class SyncMExit {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"syncM\",\n      location = @Location(value = Kind.SYNC_EXIT),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self, @ProbeClassName String pcn, @TargetInstance Object lock) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/onmethod/leveled/Throw.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces.onmethod.leveled;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Level;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeClassName;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\nimport org.openjdk.btrace.core.annotations.TargetInstance;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class Throw {\n  @OnMethod(\n      clazz = \"/.*\\\\.OnMethodTest/\",\n      method = \"exception\",\n      location = @Location(value = Kind.THROW),\n      enableAt = @Level(\">=1\"))\n  public static void args(\n      @Self Object self,\n      @ProbeClassName String pcn,\n      @ProbeMethodName String pmn,\n      @TargetInstance Throwable e) {\n    println(\"args\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/org.openjdk.btrace.xml",
    "content": "<!--\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n-->\n<btrace-probes namespace=\"org.openjdk.btrace\">\n    <probe name=\"noargs\">\n        <map>\n            <clazz>//resources\\..*//</clazz>\n            <method>callA</method>\n        </map>\n    </probe>\n    <probe name=\"withargs\">\n        <map>\n            <clazz>resources.Main</clazz>\n            <method>callB</method>\n        </map>\n    </probe>\n</btrace-probes>\n"
  },
  {
    "path": "btrace-instr/src/test/btrace/verifier/VerifierScript.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage traces.verifier;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n@BTrace\npublic class VerifierScript implements Runnable {\n  private static Properties p = new Properties();\n  private static int[] x = new int[100];\n  private int i = 10;\n\n  @OnMethod(clazz = \"/.*/\")\n  public static void invalidMethodCall(@Self List l) {\n    if (l instanceof ArrayList) {\n      System.out.println(l.size());\n    }\n  }\n\n  @OnMethod(clazz = \"/.*/\")\n  public static void invalidLoops(List<String> l) {\n    for (int i = 0; i < 10; i++) {\n      BTraceUtils.println(BTraceUtils.str(i));\n    }\n    for (String s : l) {\n      BTraceUtils.println(s);\n    }\n    while (true) {\n      BTraceUtils.print(\"x\");\n    }\n  }\n\n  @OnMethod(clazz = \"/.*/\")\n  public static int invalidReturn() {\n    return 1;\n  }\n\n  @OnMethod(clazz = \"/.*/\")\n  public static synchronized void syncHandler() {\n    synchronized (VerifierScript.class) {\n      BTraceUtils.println(\"ok\");\n    }\n  }\n\n  @OnMethod(clazz = \"/.*/\")\n  public static void validInstanceHandler() {}\n\n  @OnMethod(clazz = \"/.*/\")\n  public void invalidInstanceHandler() {\n    try {\n      System.out.println(\"x\");\n    } catch (Exception e) {\n      throw new RuntimeException(e);\n    }\n  }\n\n  @Override\n  public void run() {\n    // do nothing\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/ArgsMapTest.java",
    "content": "package org.openjdk.btrace;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.ArgsMap;\n\npublic class ArgsMapTest {\n  private static final String KEY1 = \"key1\";\n  private static final String KEY2 = \"key2\";\n  private static final String VALUE1 = \"value1\";\n  private static final String VALUE2 = \"value2\";\n\n  private ArgsMap instance;\n\n  @BeforeEach\n  public void setUp() {\n    instance = new ArgsMap();\n    instance.put(KEY1, VALUE1);\n    instance.put(KEY2, VALUE2);\n  }\n\n  @Test\n  public void templateExisting() {\n    String value = instance.template(KEY1 + \"=${\" + KEY1 + \"}\");\n    assertEquals(KEY1 + \"=\" + VALUE1, value);\n  }\n\n  @Test\n  public void templateNonExisting() {\n    String orig = KEY1 + \"=${key3}\";\n    String value = instance.template(orig);\n    assertEquals(orig, value);\n  }\n\n  @Test\n  public void templateTrailing$() {\n    String orig = KEY1 + \"$\";\n    String value = instance.template(orig);\n    assertEquals(orig, value);\n  }\n\n  @Test\n  public void templateUnclosedPlaceholder() {\n    String orig = KEY1 + \"${\";\n    String value = instance.template(orig);\n    assertEquals(orig, value);\n  }\n\n  @Test\n  public void templateSingle$() {\n    String orig = KEY1 + \"$\" + KEY2;\n    String value = instance.template(orig);\n    assertEquals(orig, value);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/BTraceProbeFactoryTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.net.URLClassLoader;\n\nimport org.junit.jupiter.api.Test;\n\nclass BTraceProbeFactoryTest {\n\n  @Test\n  void canLoadNullFile() {\n    assertFalse(BTraceProbeFactory.canLoad(null));\n  }\n\n  @Test\n  void canLoadNonExistingFile() {\n    assertFalse(BTraceProbeFactory.canLoad(\"!invalid path\"));\n  }\n\n  @Test\n  void canLoadBTracePack() throws Exception {\n    URL rsrc = BTraceProbeFactory.class.getResource(\"/resources/classdata/AllStuff.btrc\");\n    assertNotNull(rsrc);\n\n    assertTrue(BTraceProbeFactory.canLoad(new File(rsrc.toURI()).getPath()));\n  }\n\n  @Test\n  void canLoadClass() throws Exception {\n    URL rsrc = BTraceProbeFactory.class.getResource(\"BTraceProbeFactoryTest.class\");\n    assertNotNull(rsrc);\n\n    assertTrue(BTraceProbeFactory.canLoad(new File(rsrc.toURI()).getPath()));\n  }\n\n  @Test\n  void refuseUnknown() throws Exception {\n    URL rsrc = BTraceProbeFactory.class.getResource(\"/plain.txt\");\n    assertNotNull(rsrc);\n\n    assertFalse(BTraceProbeFactory.canLoad(new File(rsrc.toURI()).getPath()));\n  }\n\n  @Test\n  void canLoadFromPack() throws Exception {\n    URL jarUrl = BTraceProbeFactoryTest.class.getResource(\"/packed/test-pack.jar\");\n    assertNotNull(jarUrl);\n\n    try (URLClassLoader cl = new URLClassLoader(new URL[] {jarUrl})) {\n      assertTrue(BTraceProbeFactory.canLoad(\"io/btrace/btrace_test/AllMethods.class\", cl));\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/BTraceTransformerEarlyExitTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n */\npackage org.openjdk.btrace.instr;\n\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.DebugSupport;\nimport org.openjdk.btrace.core.SharedSettings;\n\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\n/**\n * Pins the load-bearing structural early-exit in {@link BTraceTransformer#transform}\n * for JVM-synthesized reflective accessor classes. This is the primary defense\n * against the JDK 8 reflection-inflation StackOverflowError observed in\n * testTraceAll on btraceio/btrace#830.\n *\n * <p>The early-exit must trigger regardless of class loader because synthetic\n * accessor classes are defined by {@code sun.reflect.DelegatingClassLoader} (JDK 8)\n * — neither null nor the system class loader — so the loader-gated\n * {@code isSensitiveClass()} branch in the same method does NOT filter them.\n * This test pins the loader-independence so a future refactor that accidentally\n * moves the early-exit below the loader gate will fail loudly here, even on\n * JDK 11+ build JVMs where the SOE itself is not reproducible.\n */\nclass BTraceTransformerEarlyExitTest {\n\n    private BTraceTransformer newTransformer() {\n        return new BTraceTransformer(new DebugSupport(new SharedSettings()));\n    }\n\n    /** A class loader that is neither {@code null} nor the system CL — emulates DelegatingClassLoader. */\n    private ClassLoader nonBootstrapNonSystemLoader() {\n        return new ClassLoader(null) {};\n    }\n\n    @Test\n    void sunReflectGeneratedAccessorReturnsNull() throws Exception {\n        BTraceTransformer transformer = newTransformer();\n        byte[] result = transformer.transform(\n                nonBootstrapNonSystemLoader(),\n                \"sun/reflect/GeneratedMethodAccessor42\",\n                null,\n                null,\n                new byte[]{0, 0});\n        assertNull(result, \"synthetic JDK 8 accessor must NOT be transformed (returns null)\");\n    }\n\n    @Test\n    void sunReflectGeneratedConstructorAccessorReturnsNull() throws Exception {\n        BTraceTransformer transformer = newTransformer();\n        byte[] result = transformer.transform(\n                nonBootstrapNonSystemLoader(),\n                \"sun/reflect/GeneratedConstructorAccessor7\",\n                null,\n                null,\n                new byte[]{0, 0});\n        assertNull(result, \"synthetic JDK 8 constructor accessor must NOT be transformed (returns null)\");\n    }\n\n    @Test\n    void jdkInternalReflectGeneratedAccessorReturnsNull() throws Exception {\n        BTraceTransformer transformer = newTransformer();\n        byte[] result = transformer.transform(\n                nonBootstrapNonSystemLoader(),\n                \"jdk/internal/reflect/GeneratedMethodAccessor3\",\n                null,\n                null,\n                new byte[]{0, 0});\n        assertNull(result, \"synthetic JDK 9-16 accessor must NOT be transformed (returns null)\");\n    }\n\n    @Test\n    void nullClassNameReturnsNull() throws Exception {\n        BTraceTransformer transformer = newTransformer();\n        byte[] result = transformer.transform(\n                nonBootstrapNonSystemLoader(),\n                null,\n                null,\n                null,\n                new byte[]{0, 0});\n        assertNull(result, \"classes with no binary name (JDK 8 host-anonymous, JDK 15+ hidden) must NOT be transformed\");\n    }\n\n    @Test\n    void jdk8LambdaWrapperReturnsNull() throws Exception {\n        BTraceTransformer transformer = newTransformer();\n        byte[] result = transformer.transform(\n                nonBootstrapNonSystemLoader(),\n                \"org/openjdk/btrace/agent/Main$$Lambda$36\",\n                null,\n                null,\n                new byte[]{0, 0});\n        assertNull(result, \"JDK 8 synthetic lambda wrapper (Main$$Lambda$N) must NOT be transformed\");\n    }\n\n    @Test\n    void jdk11LambdaWrapperReturnsNull() throws Exception {\n        BTraceTransformer transformer = newTransformer();\n        byte[] result = transformer.transform(\n                nonBootstrapNonSystemLoader(),\n                \"org/openjdk/btrace/agent/Main$$Lambda$12/0x00000008000ab040\",\n                null,\n                null,\n                new byte[]{0, 0});\n        assertNull(result, \"JDK 11+ synthetic lambda wrapper (Main$$Lambda$N/0x...) must NOT be transformed\");\n    }\n\n    @Test\n    void userClassWithDoubleDollarInNameIsNotSkipped() {\n        // A class whose internal name merely contains \"$$\" but NOT the specific\n        // \"$$Lambda$<digit>\" pattern is a legitimate user class (e.g. Kotlin,\n        // Scala, or Groovy synthetic) and must remain eligible for tracing.\n        // Bypassing the short-circuit ensures the regex is anchored correctly.\n        org.junit.jupiter.api.Assertions.assertFalse(\n                BTraceTransformer.isSyntheticLambda(\"com/example/My$$Bridge\"),\n                \"user class without Lambda$<digit> must NOT match the synthetic-lambda predicate\");\n        org.junit.jupiter.api.Assertions.assertFalse(\n                BTraceTransformer.isSyntheticLambda(\"com/example/My$$Lambda$\"),\n                \"malformed name with no digit after $$Lambda$ must NOT match\");\n        org.junit.jupiter.api.Assertions.assertFalse(\n                BTraceTransformer.isSyntheticLambda(\"com/example/My$$LambdaBridge\"),\n                \"substring match without the trailing $ must NOT match\");\n        org.junit.jupiter.api.Assertions.assertTrue(\n                BTraceTransformer.isSyntheticLambda(\"Foo$$Lambda$0\"),\n                \"JDK 8-style Lambda wrapper must match\");\n        org.junit.jupiter.api.Assertions.assertTrue(\n                BTraceTransformer.isSyntheticLambda(\"Foo$$Lambda$99/0xdeadbeef\"),\n                \"JDK 11+ named-hidden Lambda wrapper must match\");\n    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/CallGraphTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass CallGraphTest {\n\n  @Test\n  void hasNoCycle() {\n    CallGraph callGraph = new CallGraph();\n    callGraph.addEdge(\"a\", \"b\");\n    callGraph.addEdge(\"a\", \"c\");\n    callGraph.addEdge(\"b\", \"d\");\n    callGraph.addEdge(\"c\", \"d\");\n\n    assertFalse(callGraph.hasCycle());\n  }\n\n  @Test\n  void hasNoCycleWithIsolatedNode() {\n    CallGraph callGraph = new CallGraph();\n    callGraph.addStarting(\"a\");\n    callGraph.addStarting(\"b\");\n    callGraph.addStarting(\"c\");\n\n    callGraph.addEdge(\"a\", \"d\");\n    callGraph.addEdge(\"b\", \"d\");\n\n    assertFalse(callGraph.hasCycle());\n  }\n\n  @Test\n  void hasCycleFromRootNode() {\n    CallGraph callGraph = new CallGraph();\n    callGraph.addEdge(\"a\", \"b\");\n    callGraph.addEdge(\"a\", \"c\");\n    callGraph.addEdge(\"b\", \"d\");\n    callGraph.addEdge(\"c\", \"d\");\n    callGraph.addEdge(\"c\", \"b\");\n    callGraph.addEdge(\"d\", \"a\");\n    callGraph.addStarting(\"a\");\n\n    assertTrue(callGraph.hasCycle());\n  }\n\n  @Test\n  void hasCycle() {\n    CallGraph callGraph = new CallGraph();\n    callGraph.addEdge(\"a\", \"b\");\n    callGraph.addEdge(\"a\", \"c\");\n    callGraph.addEdge(\"b\", \"d\");\n    callGraph.addEdge(\"c\", \"d\");\n    callGraph.addEdge(\"c\", \"b\");\n    callGraph.addEdge(\"d\", \"b\");\n    callGraph.addStarting(\"a\");\n\n    assertTrue(callGraph.hasCycle());\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/ClassCacheTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.Map;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass ClassCacheTest {\n  private ClassCache instance;\n\n  @BeforeEach\n  void setup() {\n    instance = new ClassCache(10);\n  }\n\n  @Test\n  void getClazz() {\n    ClassInfo ci = instance.get(String.class);\n    assertNotNull(ci);\n\n    ClassInfo ci1 = instance.get(String.class);\n\n    assertEquals(ci1, ci);\n  }\n\n  @Test\n  void getClazzNullCL() {\n    ClassInfo ci = instance.get(null, String.class.getName());\n    assertNotNull(ci);\n  }\n\n  @Test\n  void testCacheCleanup() throws Exception {\n    ClassLoader cl = new ClassLoader(ClassCacheTest.class.getClassLoader()) {};\n\n    Map<ClassInfo.ClassName, ClassInfo> infos = instance.getInfos(cl);\n\n    assertNotNull(infos);\n    assertTrue(infos.isEmpty());\n    assertEquals(1, instance.getSize());\n\n    // run GC but have the classloader still referred to\n    System.gc();\n    Thread.sleep(100);\n\n    assertEquals(1, instance.getSize());\n\n    // clear the reference to the classloader\n    cl = null;\n    // and run the gc\n    System.gc();\n    Thread.sleep(100);\n\n    assertEquals(0, instance.getSize());\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/ClassFilterSensitiveTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n */\npackage org.openjdk.btrace.instr;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * Pins the sensitive-class filter entries that protect against the JDK 8\n * reflection-inflation StackOverflowError. When the agent makes any reflective\n * Method.invoke() past the inflation threshold, the JVM defines a synthetic\n * accessor class under sun/reflect/Generated* (JDK 8) or jdk/internal/reflect/\n * Generated* (JDK 9-16). If those classes are not filtered, BTraceTransformer\n * will instrument them, ASM frame computation will issue more reflective calls,\n * the cascade recurses, and the agent crashes during testTraceAll on JDK 8.\n *\n * Coverage is loader-independent because synthetic accessors are defined in\n * sun.reflect.DelegatingClassLoader (not bootstrap, not system); the\n * structural early-exit in BTraceTransformer.transform() ALSO does not depend\n * on loader, but this test pins the SENSITIVE_CLASSES list as defense-in-depth\n * against future refactors of the transformer entry path.\n */\nclass ClassFilterSensitiveTest {\n\n    @Test\n    void sunReflectGeneratedAccessorIsSensitive() {\n        assertTrue(ClassFilter.isSensitiveClass(\"sun/reflect/GeneratedMethodAccessor42\"),\n                \"sun/reflect/GeneratedMethodAccessor* must be sensitive — instrumenting it triggers JDK 8 inflation cascade\");\n        assertTrue(ClassFilter.isSensitiveClass(\"sun/reflect/GeneratedConstructorAccessor1\"),\n                \"sun/reflect/GeneratedConstructorAccessor* must be sensitive — same cascade source via constructor inflation\");\n        assertTrue(ClassFilter.isSensitiveClass(\"sun/reflect/GeneratedSerializationConstructorAccessor7\"),\n                \"sun/reflect/GeneratedSerializationConstructorAccessor* must be sensitive — same cascade source\");\n    }\n\n    @Test\n    void jdkInternalReflectIsSensitive() {\n        assertTrue(ClassFilter.isSensitiveClass(\"jdk/internal/reflect/GeneratedMethodAccessor3\"),\n                \"JDK 9-16 renames the synthetic accessors under jdk/internal/reflect — must be sensitive too\");\n    }\n\n    @Test\n    void appClassesAreNotSensitive() {\n        assertFalse(ClassFilter.isSensitiveClass(\"com/example/MyApp\"),\n                \"Ordinary application classes must not be filtered\");\n        assertFalse(ClassFilter.isSensitiveClass(\"org/junit/jupiter/api/Test\"),\n                \"Library classes outside the sensitive prefixes must not be filtered\");\n    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/ClassInfoTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport java.lang.reflect.Method;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ClassInfoTest {\n    @BeforeAll\n    static void setupAll() throws Throwable {\n        Class<?> accessImpl = Class.forName(\"org.openjdk.btrace.runtime.BTraceRuntimeAccessImpl\");\n        Method m = accessImpl.getDeclaredMethod(\"install\");\n        m.setAccessible(true);\n        m.invoke(null);\n    }\n\n    @Test\n    void isBootstrap() {\n        assertTrue(ClassInfo.isBootstrap(String.class.getName()));\n        assertFalse(ClassInfo.isBootstrap(ClassInfoTest.class.getName()));\n    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/ExtensionBootstrapTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport org.junit.jupiter.api.Test;\n\npublic class ExtensionBootstrapTest {\n\n  @Test\n  public void bootstrapInvoke() {}\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/HandlerRepositoryImplTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.lang.invoke.CallSite;\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.MethodType;\nimport java.lang.invoke.MutableCallSite;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.HandlerRepository;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.runtime.IndyDispatcher;\n\n/**\n * Lifecycle and dispatch tests for HandlerRepositoryImpl + IndyDispatcher.\n *\n * <p>Covers register/unregister lifecycle, successful resolution via a loadable probe\n * class, IndyDispatcher.bootstrap() happy path (ConstantCallSite), and the\n * self-relinking MutableCallSite path for register-after-bootstrap races.\n */\n// NB: must be `public` — publicLookup() can only resolve methods on public classes, and the\n// happy-path tests use this class itself as the stand-in probe class.\npublic class HandlerRepositoryImplTest {\n\n  /** Minimal stub BTraceProbe for lifecycle-only tests. */\n  private static BTraceProbe stubProbe(String internalName) {\n    return stubProbe(internalName, null);\n  }\n\n  /**\n   * Stub {@link BTraceProbe} that returns {@code probeClass} from {@code getProbeClass()}.\n   * Use when a test needs resolution to succeed against a specific loadable class (the\n   * production resolver reads the class via {@code probe.getProbeClass()}).\n   */\n  private static BTraceProbe stubProbe(String internalName, Class<?> probeClass) {\n    return new BTraceProbe() {\n      @Override public String getClassName() { return internalName.replace('/', '.'); }\n      @Override public String getClassName(boolean internal) {\n        return internal ? internalName : internalName.replace('/', '.');\n      }\n      @Override public boolean isTransforming() { return false; }\n      @Override public boolean isClassRenamed() { return false; }\n      @Override public boolean isVerified() { return true; }\n      @Override public void checkVerified() {}\n      @Override public Collection<OnMethod> getApplicableHandlers(BTraceClassReader cr) { return Collections.emptyList(); }\n      @Override public Iterable<OnMethod> onmethods() { return Collections.emptyList(); }\n      @Override public Iterable<OnProbe> onprobes() { return Collections.emptyList(); }\n      @Override public Class<?> register(BTraceRuntime.Impl rt, BTraceTransformer t) { return probeClass; }\n      @Override public Class<?> getProbeClass() { return probeClass; }\n      @Override public void unregister() {}\n      @Override public byte[] getFullBytecode() { return new byte[0]; }\n      @Override public byte[] getDataHolderBytecode() { return new byte[0]; }\n      @Override public BTraceRuntime.Impl getRuntime() { return null; }\n      @Override public boolean willInstrument(Class<?> clz) { return false; }\n      @Override public String getActionPrefix() { return \"\"; }\n      @Override public void notifyTransform(String className) {}\n      @Override public void copyHandlers(org.objectweb.asm.ClassVisitor cv) {}\n      @Override public void applyArgs(ArgsMap argsMap) {}\n      @Override public Set<Permission> getRequiredPermissions() { return Collections.emptySet(); }\n    };\n  }\n\n  /**\n   * Public static handler used by the happy-path resolution test. The production resolver\n   * strips the {@code probeName$} prefix from the handler name, so the call-site handler\n   * name is {@code \"HandlerRepositoryImplTest$ping\"} but the actual method is {@code ping}.\n   */\n  public static void ping() { HANDLER_CALLED.set(true); }\n\n  private static final AtomicBoolean HANDLER_CALLED = new AtomicBoolean();\n\n  @AfterEach\n  void cleanup() {\n    HANDLER_CALLED.set(false);\n  }\n\n  @Test\n  void testGetProbeClassExposesClassOnStubProbe() {\n    BTraceProbe probe = stubProbe(\"test/accessor/StubProbe\", HandlerRepositoryImplTest.class);\n    assertSame(HandlerRepositoryImplTest.class, probe.getProbeClass());\n  }\n\n  @Test\n  void testRegisterAndResolveReturnsNullForUnknownHandler() {\n    String probeName = \"test/lifecycle/StubProbe\";\n    BTraceProbe probe = stubProbe(probeName);\n    try {\n      HandlerRepositoryImpl.registerProbe(probe);\n      MethodHandle result = HandlerRepositoryImpl.resolveHandler(\n          probeName, \"onMethod\", MethodType.methodType(void.class));\n      assertNull(result, \"Should return null when probe class cannot be loaded\");\n    } finally {\n      HandlerRepositoryImpl.unregisterProbe(probe);\n    }\n  }\n\n  @Test\n  void testUnregisterClearsCacheForProbe() {\n    String probeName = \"test/lifecycle/AnotherProbe\";\n    BTraceProbe probe = stubProbe(probeName);\n    HandlerRepositoryImpl.registerProbe(probe);\n    HandlerRepositoryImpl.resolveHandler(\n        probeName, \"someHandler\", MethodType.methodType(void.class));\n    HandlerRepositoryImpl.unregisterProbe(probe);\n\n    MethodHandle afterUnregister = HandlerRepositoryImpl.resolveHandler(\n        probeName, \"someHandler\", MethodType.methodType(void.class));\n    assertNull(afterUnregister, \"Should return null after probe is unregistered\");\n  }\n\n  @Test\n  void testUnregisterDoesNotAffectOtherProbes() {\n    String probeName1 = \"test/lifecycle/ProbeOne\";\n    String probeName2 = \"test/lifecycle/ProbeTwo\";\n    BTraceProbe probe1 = stubProbe(probeName1);\n    BTraceProbe probe2 = stubProbe(probeName2);\n    try {\n      HandlerRepositoryImpl.registerProbe(probe1);\n      HandlerRepositoryImpl.registerProbe(probe2);\n      HandlerRepositoryImpl.resolveHandler(probeName1, \"handler\", MethodType.methodType(void.class));\n      HandlerRepositoryImpl.resolveHandler(probeName2, \"handler\", MethodType.methodType(void.class));\n      HandlerRepositoryImpl.unregisterProbe(probe1);\n      assertNotNull(probe2);\n    } finally {\n      HandlerRepositoryImpl.unregisterProbe(probe2);\n    }\n  }\n\n  /**\n   * Success path: register a probe whose internal name points at this test class (loadable,\n   * has a matching public static method). Verify resolveHandler returns a live, invocable MH.\n   */\n  @Test\n  void testResolvesRealHandlerFromLoadedClass() throws Throwable {\n    String probeName = HandlerRepositoryImplTest.class.getName().replace('.', '/');\n    BTraceProbe probe = stubProbe(probeName, HandlerRepositoryImplTest.class);\n    try {\n      HandlerRepositoryImpl.registerProbe(probe);\n\n      MethodHandle mh = HandlerRepositoryImpl.resolveHandler(\n          probeName,\n          \"HandlerRepositoryImplTest$ping\",\n          MethodType.methodType(void.class));\n\n      assertNotNull(mh, \"resolveHandler should succeed when probe class has matching static method\");\n      mh.invokeExact();\n      assertTrue(HANDLER_CALLED.get(), \"Resolved handler should invoke the target method\");\n    } finally {\n      HandlerRepositoryImpl.unregisterProbe(probe);\n    }\n  }\n\n  /**\n   * Bootstrap happy path: every call site is a MutableCallSite (so it can be re-linked\n   * to a noop on unregister). On immediate resolution the target is the resolved handle.\n   */\n  @Test\n  void testBootstrapReturnsMutableCallSiteOnImmediateResolution() throws Throwable {\n    String probeName = HandlerRepositoryImplTest.class.getName().replace('.', '/');\n    BTraceProbe probe = stubProbe(probeName, HandlerRepositoryImplTest.class);\n    try {\n      HandlerRepositoryImpl.registerProbe(probe);\n\n      CallSite cs = IndyDispatcher.bootstrap(\n          MethodHandles.lookup(),\n          \"HandlerRepositoryImplTest$ping\",\n          MethodType.methodType(void.class),\n          probeName);\n\n      assertTrue(cs instanceof MutableCallSite,\n          \"Expected MutableCallSite so unregister can re-link to noop; got: \" + cs.getClass());\n      cs.dynamicInvoker().invokeExact();\n      assertTrue(HANDLER_CALLED.get(), \"MutableCallSite target must invoke the resolved handler\");\n    } finally {\n      HandlerRepositoryImpl.unregisterProbe(probe);\n    }\n  }\n\n  /**\n   * Crash-safety regression: after a probe is unregistered, any previously-linked call\n   * site targeting it must stop invoking the handler body (so the instrumented app is not\n   * exposed to half-torn-down BTraceRuntime state). This is the dispatch-level equivalent\n   * of the older \"cushion\" approach that stubbed probe method bodies via bytecode redefine.\n   */\n  @Test\n  void testUnregisterRelinksLiveCallSiteToNoop() throws Throwable {\n    String probeName = HandlerRepositoryImplTest.class.getName().replace('.', '/');\n    BTraceProbe probe = stubProbe(probeName, HandlerRepositoryImplTest.class);\n    HandlerRepositoryImpl.registerProbe(probe);\n\n    CallSite cs = IndyDispatcher.bootstrap(\n        MethodHandles.lookup(),\n        \"HandlerRepositoryImplTest$ping\",\n        MethodType.methodType(void.class),\n        probeName);\n    // Sanity: handler fires before unregister.\n    cs.dynamicInvoker().invokeExact();\n    assertTrue(HANDLER_CALLED.get(), \"Handler must fire while probe is registered\");\n    HANDLER_CALLED.set(false);\n\n    HandlerRepositoryImpl.unregisterProbe(probe);\n\n    // After unregister the live call site must no longer run the handler body.\n    cs.dynamicInvoker().invokeExact();\n    assertFalse(HANDLER_CALLED.get(),\n        \"Handler must NOT fire after unregister — call site must be relinked to noop\");\n  }\n\n  /**\n   * Unregistering probe A must not affect a live call site targeting probe B. Tests the\n   * per-probe scoping of {@code IndyDispatcher.invalidateProbe}.\n   */\n  @Test\n  void testUnregisterProbeADoesNotInvalidateProbeB() throws Throwable {\n    // Probe A: stubProbe with a name that is not loadable — we only need to verify that\n    // invalidateProbe doesn't touch probe B's sites.\n    String probeAName = \"test/unrelated/ProbeA\";\n    BTraceProbe probeA = stubProbe(probeAName);\n    HandlerRepositoryImpl.registerProbe(probeA);\n\n    // Probe B: this test class — actually resolves a real handler.\n    String probeBName = HandlerRepositoryImplTest.class.getName().replace('.', '/');\n    BTraceProbe probeB = stubProbe(probeBName, HandlerRepositoryImplTest.class);\n    HandlerRepositoryImpl.registerProbe(probeB);\n    try {\n      CallSite csB = IndyDispatcher.bootstrap(\n          MethodHandles.lookup(),\n          \"HandlerRepositoryImplTest$ping\",\n          MethodType.methodType(void.class),\n          probeBName);\n      csB.dynamicInvoker().invokeExact();\n      assertTrue(HANDLER_CALLED.get(), \"Probe B handler fires before any unregister\");\n      HANDLER_CALLED.set(false);\n\n      // Unregistering probe A must leave probe B's site intact.\n      HandlerRepositoryImpl.unregisterProbe(probeA);\n\n      csB.dynamicInvoker().invokeExact();\n      assertTrue(HANDLER_CALLED.get(),\n          \"Probe B call site must survive unrelated probe A unregister\");\n    } finally {\n      HandlerRepositoryImpl.unregisterProbe(probeB);\n    }\n  }\n\n  /**\n   * Two live call sites on the same probe: unregister must relink BOTH. Guards against a\n   * registry bug where only the most recent site is invalidated.\n   */\n  @Test\n  void testUnregisterRelinksAllLiveSitesForProbe() throws Throwable {\n    String probeName = HandlerRepositoryImplTest.class.getName().replace('.', '/');\n    BTraceProbe probe = stubProbe(probeName, HandlerRepositoryImplTest.class);\n    HandlerRepositoryImpl.registerProbe(probe);\n\n    CallSite cs1 = IndyDispatcher.bootstrap(\n        MethodHandles.lookup(),\n        \"HandlerRepositoryImplTest$ping\",\n        MethodType.methodType(void.class),\n        probeName);\n    CallSite cs2 = IndyDispatcher.bootstrap(\n        MethodHandles.lookup(),\n        \"HandlerRepositoryImplTest$ping\",\n        MethodType.methodType(void.class),\n        probeName);\n\n    // Warm both.\n    cs1.dynamicInvoker().invokeExact();\n    assertTrue(HANDLER_CALLED.get()); HANDLER_CALLED.set(false);\n    cs2.dynamicInvoker().invokeExact();\n    assertTrue(HANDLER_CALLED.get()); HANDLER_CALLED.set(false);\n\n    HandlerRepositoryImpl.unregisterProbe(probe);\n\n    cs1.dynamicInvoker().invokeExact();\n    assertFalse(HANDLER_CALLED.get(), \"Site 1 must be relinked on unregister\");\n    cs2.dynamicInvoker().invokeExact();\n    assertFalse(HANDLER_CALLED.get(), \"Site 2 must also be relinked on unregister\");\n  }\n\n  /**\n   * F01/F02/F03 regression: bootstrap() before registration returns a MutableCallSite that\n   * is a no-op while unresolved but self-heals after the probe is registered. No permanent\n   * noop trap.\n   */\n  @Test\n  void testBootstrapBeforeRegistrationHealsViaMutableCallSite() throws Throwable {\n    String probeName = HandlerRepositoryImplTest.class.getName().replace('.', '/');\n\n    CallSite cs = IndyDispatcher.bootstrap(\n        MethodHandles.lookup(),\n        \"HandlerRepositoryImplTest$ping\",\n        MethodType.methodType(void.class),\n        probeName);\n    assertTrue(cs instanceof MutableCallSite,\n        \"Expected MutableCallSite when resolution cannot succeed yet, got: \" + cs.getClass());\n\n    cs.dynamicInvoker().invokeExact();\n    assertFalse(HANDLER_CALLED.get(), \"Handler must not fire while probe is unregistered\");\n\n    BTraceProbe probe = stubProbe(probeName, HandlerRepositoryImplTest.class);\n    try {\n      HandlerRepositoryImpl.registerProbe(probe);\n\n      cs.dynamicInvoker().invokeExact();\n      assertTrue(HANDLER_CALLED.get(),\n          \"MutableCallSite must self-heal and invoke handler after registration\");\n\n      HANDLER_CALLED.set(false);\n      cs.dynamicInvoker().invokeExact();\n      assertTrue(HANDLER_CALLED.get(), \"Relinked target must remain resolved on subsequent calls\");\n    } finally {\n      HandlerRepositoryImpl.unregisterProbe(probe);\n    }\n  }\n\n  /** Null repository returns a MutableCallSite that no-ops without crashing. */\n  @Test\n  void testBootstrapWithNullRepositoryDoesNotCrash() throws Throwable {\n    HandlerRepository saved = IndyDispatcher.repository;\n    try {\n      IndyDispatcher.repository = null;\n      CallSite cs = IndyDispatcher.bootstrap(\n          MethodHandles.lookup(),\n          \"probe$handler\",\n          MethodType.methodType(void.class),\n          \"nonexistent/Probe\");\n      assertTrue(cs instanceof MutableCallSite,\n          \"Null-repository path must return MutableCallSite (self-healing), not ConstantCallSite\");\n      cs.dynamicInvoker().invokeExact(); // must not throw\n    } finally {\n      IndyDispatcher.repository = saved;\n    }\n  }\n\n  @Test\n  void testResolveHandlerUsesProbeClassAccessorNotClassForName() throws Throwable {\n    // Use a probeName that is NOT resolvable by Class.forName (no such class exists),\n    // but pass the test class as the getProbeClass() value. If resolveHandler still\n    // returns a live MethodHandle, it means resolution went through probe.getProbeClass()\n    // and bypassed any Class.forName lookup of the fake probe name.\n    String unresolvableProbeName = \"non/existent/FakeProbe$\" + System.nanoTime();\n    BTraceProbe probe = stubProbe(unresolvableProbeName, HandlerRepositoryImplTest.class);\n    try {\n      HandlerRepositoryImpl.registerProbe(probe);\n      MethodHandle mh = HandlerRepositoryImpl.resolveHandler(\n          unresolvableProbeName,\n          \"FakeProbe$ping\",\n          MethodType.methodType(void.class));\n      assertNotNull(mh,\n          \"resolveHandler must find handler via probe.getProbeClass(), not via Class.forName(probeName)\");\n      mh.invokeExact();\n      assertTrue(HANDLER_CALLED.get(), \"Resolved handler must invoke the test's ping()\");\n    } finally {\n      HandlerRepositoryImpl.unregisterProbe(probe);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/InstrStackTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\nimport org.objectweb.asm.ClassWriter;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\n\nimport java.util.stream.Stream;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\n\npublic class InstrStackTest {\n    InstrumentingMethodVisitor instance;\n\n    @BeforeEach\n    void setup() throws Exception {\n        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);\n        cw.visit(Opcodes.ASM9, Opcodes.ACC_PUBLIC, \"test.Test\", null, null, null);\n        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, \"test\", \"()V\", null, null);\n        instance = new InstrumentingMethodVisitor(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, \"test.Test\", \"test\", \"()V\", mv);\n    }\n\n    @Test\n    void ACONST_NULL() {\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        assertEquals(Opcodes.NULL, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void ICONST_1() {\n        instance.visitInsn(Opcodes.ICONST_1);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void ICONST_2() {\n        instance.visitInsn(Opcodes.ICONST_2);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void ICONST_3() {\n        instance.visitInsn(Opcodes.ICONST_3);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void ICONST_4() {\n        instance.visitInsn(Opcodes.ICONST_4);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void ICONST_5() {\n        instance.visitInsn(Opcodes.ICONST_5);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void ICONST_M1() {\n        instance.visitInsn(Opcodes.ICONST_M1);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void FCONST_0() {\n        instance.visitInsn(Opcodes.FCONST_0);\n        assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n    }\n    @Test\n    void FCONST_1() {\n        instance.visitInsn(Opcodes.FCONST_1);\n        assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n    }\n    @Test\n    void FCONST_2() {\n        instance.visitInsn(Opcodes.FCONST_2);\n        assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n    }\n    @Test\n    void DCONST_0() {\n        instance.visitInsn(Opcodes.DCONST_0);\n        InstrumentingMethodVisitor.Introspection  i = instance.introspect();\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n        assertEquals(Opcodes.DOUBLE, i.stack.peekX1());\n    }\n    @Test\n    void DCONST_1() {\n        instance.visitInsn(Opcodes.DCONST_1);\n        InstrumentingMethodVisitor.Introspection  i = instance.introspect();\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n        assertEquals(Opcodes.DOUBLE, i.stack.peekX1());\n    }\n    @Test\n    void LCONST_0() {\n        instance.visitInsn(Opcodes.LCONST_0);\n        InstrumentingMethodVisitor.Introspection  i = instance.introspect();\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n        assertEquals(Opcodes.LONG, i.stack.peekX1());\n    }\n    @Test\n    void LCONST_1() {\n        instance.visitInsn(Opcodes.LCONST_1);\n        InstrumentingMethodVisitor.Introspection  i = instance.introspect();\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n        assertEquals(Opcodes.LONG, i.stack.peekX1());\n    }\n    @Test\n    void AALOAD() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"java/lang/String\");\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.AALOAD);\n        assertEquals(\"java/lang/String\", instance.introspect().stack.peek());\n    }\n    @Test\n    void AALOAD_TYPEDESC() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"Ljava/lang/String;\");\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.AALOAD);\n        assertEquals(\"java/lang/String\", instance.introspect().stack.peek());\n    }\n    @Test\n    void AALOAD_NULL() {\n        instance.visitLdcInsn(1);\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.AALOAD);\n        assertEquals(Opcodes.NULL, instance.introspect().stack.peek());\n    }\n    @Test\n    void AALOAD_INVALID() {\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.AALOAD);\n        assertEquals(\"java/lang/Object\", instance.introspect().stack.peek());\n    }\n    @Test\n    void IALOAD() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"I\");\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.IALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void IALOAD_NULL() {\n        instance.visitLdcInsn(1);\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.IALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void IALOAD_INVALID() {\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.IALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void FALOAD() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"F\");\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.FALOAD);\n        assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n    }\n    @Test\n    void FALOAD_NULL() {\n        instance.visitLdcInsn(1);\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.FALOAD);\n        assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n    }\n    @Test\n    void FALOAD_INVALID() {\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.FALOAD);\n        assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n    }\n    @Test\n    void BALOAD() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"B\");\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.BALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void BALOAD_NULL() {\n        instance.visitLdcInsn(1);\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.BALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void BALOAD_INVALID() {\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.BALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void CALOAD() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"C\");\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.CALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void CALOAD_NULL() {\n        instance.visitLdcInsn(1);\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.CALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void CALOAD_INVALID() {\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.CALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void SALOAD() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"S\");\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.SALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void SALOAD_NULL() {\n        instance.visitLdcInsn(1);\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.SALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void SALOAD_INVALID() {\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.SALOAD);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n    @Test\n    void LALOAD() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"J\");\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.LALOAD);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n        assertEquals(Opcodes.LONG, i.stack.peekX1());\n    }\n    @Test\n    void LALOAD_NULL() {\n        instance.visitLdcInsn(1);\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.LALOAD);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n        assertEquals(Opcodes.LONG, i.stack.peekX1());\n    }\n    @Test\n    void LALOAD_INVALID() {\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.LALOAD);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n        assertEquals(Opcodes.LONG, i.stack.peekX1());\n    }\n\n    @Test\n    void DALOAD() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"D\");\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.DALOAD);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n        assertEquals(Opcodes.DOUBLE, i.stack.peekX1());\n    }\n    @Test\n    void DALOAD_NULL() {\n        instance.visitLdcInsn(1);\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.DALOAD);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n        assertEquals(Opcodes.DOUBLE, i.stack.peekX1());\n    }\n    @Test\n    void DALOAD_INVALID() {\n        instance.visitLdcInsn(0);\n        instance.visitInsn(Opcodes.DALOAD);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n        assertEquals(Opcodes.DOUBLE, i.stack.peekX1());\n    }\n\n    @Test\n    void AASTORE() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"java/lang/String\"); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(\"hello\"); // value\n        instance.visitInsn(Opcodes.AASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void AASTORE_TYPEDESC() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"Ljava/lang/String;\"); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(\"hello\"); // value\n        instance.visitInsn(Opcodes.AASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void AASTORE_NULL() {\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(\"hello\"); // value\n        instance.visitInsn(Opcodes.AASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void AASTORE_INVALID() {\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(\"hello\"); // value\n        instance.visitInsn(Opcodes.AASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void IASTORE() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"I\"); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.IASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void IASTORE_NULL() {\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.IASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void IASTORE_INVALID() {\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.IASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void BASTORE() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"B\"); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.BASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void BASTORE_NULL() {\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.BASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void BASTORE_INVALID() {\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.BASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n    @Test\n    void CASTORE() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"C\"); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.CASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void CASTORE_NULL() {\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.CASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void CASTORE_INVALID() {\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.CASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void SASTORE() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"S\"); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.SASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void SASTORE_NULL() {\n        instance.visitInsn(Opcodes.ACONST_NULL);\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.SASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void SASTORE_INVALID() {\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.SASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void FASTORE() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"F\"); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1f); // value\n        instance.visitInsn(Opcodes.FASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void FASTORE_NULL() {\n        instance.visitInsn(Opcodes.ACONST_NULL); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1f); // value\n        instance.visitInsn(Opcodes.FASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void FASTORE_INVALID() {\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1f); // value\n        instance.visitInsn(Opcodes.FASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void LASTORE() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"J\"); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1L); // value\n        instance.visitInsn(Opcodes.LASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void LASTORE_NULL() {\n        instance.visitInsn(Opcodes.ACONST_NULL); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1L); // value\n        instance.visitInsn(Opcodes.LASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void LASTORE_INVALID() {\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.LASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n\n    @Test\n    void DASTORE() {\n        instance.visitLdcInsn(1);\n        instance.visitTypeInsn(Opcodes.ANEWARRAY, \"D\"); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1d); // value\n        instance.visitInsn(Opcodes.DASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void DASTORE_NULL() {\n        instance.visitInsn(Opcodes.ACONST_NULL); // arrayref\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1d); // value\n        instance.visitInsn(Opcodes.DASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void DASTORE_INVALID() {\n        instance.visitLdcInsn(0); // index\n        instance.visitLdcInsn(1); // value\n        instance.visitInsn(Opcodes.DASTORE);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void POP() {\n        instance.visitLdcInsn(1);\n        instance.visitLdcInsn(\"hello\");\n        instance.visitInsn(Opcodes.POP);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.POP);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.POP);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void POP2() {\n        instance.visitLdcInsn(1);\n        instance.visitLdcInsn(2);\n        instance.visitInsn(Opcodes.POP2);\n        assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n\n        instance.visitLdcInsn(1);\n        instance.visitLdcInsn(2L);\n        instance.visitInsn(Opcodes.POP2);\n        assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n    }\n\n    @Test\n    void DUP() {\n        instance.visitLdcInsn(1);\n        instance.visitInsn(Opcodes.DUP);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n\n        assertEquals(2, i.stack.size());\n        assertEquals(Opcodes.INTEGER, i.stack.peek());\n    }\n\n    @Test\n    void DUP_X1() {\n        instance.visitLdcInsn(1);\n        instance.visitLdcInsn(\"hello\");\n        instance.visitLdcInsn(2f);\n\n        assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.DUP_X1);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(4, i.stack.size());\n        assertEquals(Opcodes.FLOAT, i.stack.peek(2));\n    }\n\n    @Test\n    void DUP_X2() {\n        instance.visitLdcInsn(1);\n        instance.visitLdcInsn(\"hello\");\n        instance.visitLdcInsn(2f);\n\n        assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.DUP_X2);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(4, i.stack.size());\n        assertEquals(Opcodes.FLOAT, i.stack.peek(3));\n    }\n\n    @Test\n    void DUP_X2_LONG() {\n        instance.visitLdcInsn(\"hello\");\n        instance.visitLdcInsn(1L);\n        instance.visitLdcInsn(2f);\n\n        assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.DUP_X2);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(5, i.stack.size());\n        assertEquals(Opcodes.FLOAT, i.stack.peek(3));\n    }\n\n    @Test\n    void DUP2() {\n        instance.visitLdcInsn(1);\n        instance.visitLdcInsn(2f);\n        assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.DUP2);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(4, i.stack.size());\n        assertEquals(Opcodes.FLOAT, i.stack.peek());\n        assertEquals(Opcodes.INTEGER, i.stack.peek(1));\n    }\n\n    @Test\n    void DUP2_LONG() {\n        instance.visitLdcInsn(1L);\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.DUP2);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(4, i.stack.size());\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n        assertEquals(Opcodes.LONG, i.stack.peek(1));\n    }\n\n    @Test\n    void DUP2_X1() {\n        instance.visitLdcInsn(1);\n        instance.visitLdcInsn(2f);\n        instance.visitLdcInsn(\"hello\");\n\n        assertEquals(\"java/lang/String\", instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.DUP2_X1);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(5, i.stack.size());\n        assertEquals(\"java/lang/String\", i.stack.peek(3));\n        assertEquals(Opcodes.FLOAT, i.stack.peek(4));\n    }\n\n    @Test\n    void DUP2_X1_LONG() {\n        instance.visitLdcInsn(1);\n        instance.visitLdcInsn(2L);\n\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.DUP2_X1);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(5, i.stack.size());\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek(3));\n        assertEquals(Opcodes.LONG, i.stack.peek(4));\n    }\n\n    @Test\n    void DUP2_X2() {\n        instance.visitLdcInsn(0);\n        instance.visitLdcInsn(1);\n        instance.visitLdcInsn(2f);\n        instance.visitLdcInsn(\"hello\");\n\n        assertEquals(\"java/lang/String\", instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.DUP2_X2);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(6, i.stack.size());\n        assertEquals(\"java/lang/String\", i.stack.peek(4));\n        assertEquals(Opcodes.FLOAT, i.stack.peek(5));\n    }\n\n    @Test\n    void DUP2_X2_LONG() {\n        instance.visitLdcInsn(0);\n        instance.visitLdcInsn(1);\n        instance.visitLdcInsn(2L);\n\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.DUP2_X2);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(6, i.stack.size());\n        assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek(4));\n        assertEquals(Opcodes.LONG, i.stack.peek(5));\n    }\n\n    @Test\n    void SWAP() {\n        instance.visitLdcInsn(1);\n        instance.visitLdcInsn(2f);\n\n        assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n\n        instance.visitInsn(Opcodes.SWAP);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(2, i.stack.size());\n        assertEquals(Opcodes.INTEGER, i.stack.peek());\n        assertEquals(Opcodes.FLOAT, i.stack.peek(1));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"arithmeticOpArguments\")\n    void ADD(Type type, int stackType, Object left, Object right) {\n        instance.visitLdcInsn(left);\n        instance.visitLdcInsn(right);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackType, type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        instance.visitInsn(type.getOpcode(Opcodes.IADD));\n        i = instance.introspect();\n        assertEquals(type.getSize(), i.stack.size());\n        Object slotType = type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackType, slotType);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"arithmeticOpArguments\")\n    void SUB(Type type, int stackType, Object left, Object right) {\n        instance.visitLdcInsn(left);\n        instance.visitLdcInsn(right);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackType, type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        instance.visitInsn(type.getOpcode(Opcodes.ISUB));\n        i = instance.introspect();\n        assertEquals(type.getSize(), i.stack.size());\n        Object slotType = type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackType, slotType);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"arithmeticOpArguments\")\n    void MUL(Type type, int stackType, Object left, Object right) {\n        instance.visitLdcInsn(left);\n        instance.visitLdcInsn(right);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackType, type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        instance.visitInsn(type.getOpcode(Opcodes.IMUL));\n        i = instance.introspect();\n        assertEquals(type.getSize(), i.stack.size());\n        Object slotType = type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackType, slotType);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"arithmeticOpArguments\")\n    void DIV(Type type, int stackType, Object left, Object right) {\n        instance.visitLdcInsn(left);\n        instance.visitLdcInsn(right);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackType, type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        instance.visitInsn(type.getOpcode(Opcodes.IDIV));\n        i = instance.introspect();\n        assertEquals(type.getSize(), i.stack.size());\n        Object slotType = type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackType, slotType);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"arithmeticOpArguments\")\n    void REM(Type type, int stackType, Object left, Object right) {\n        instance.visitLdcInsn(left);\n        instance.visitLdcInsn(right);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackType, type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        instance.visitInsn(type.getOpcode(Opcodes.IREM));\n        i = instance.introspect();\n        assertEquals(type.getSize(), i.stack.size());\n        Object slotType = type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackType, slotType);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"bitwiseOpArguments\")\n    void OR(Type type, int stackType, Object left, Object right) {\n        instance.visitLdcInsn(left);\n        instance.visitLdcInsn(right);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackType, type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        instance.visitInsn(type.getOpcode(Opcodes.IOR));\n        i = instance.introspect();\n        assertEquals(type.getSize(), i.stack.size());\n        Object slotType = type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackType, slotType);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"bitwiseOpArguments\")\n    void AND(Type type, int stackType, Object left, Object right) {\n        instance.visitLdcInsn(left);\n        instance.visitLdcInsn(right);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackType, type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        instance.visitInsn(type.getOpcode(Opcodes.IAND));\n        i = instance.introspect();\n        assertEquals(type.getSize(), i.stack.size());\n        Object slotType = type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackType, slotType);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"bitwiseOpArguments\")\n    void XOR(Type type, int stackType, Object left, Object right) {\n        instance.visitLdcInsn(left);\n        instance.visitLdcInsn(right);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackType, type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        instance.visitInsn(type.getOpcode(Opcodes.IXOR));\n        i = instance.introspect();\n        assertEquals(type.getSize(), i.stack.size());\n        Object slotType = type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackType, slotType);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"bitwiseOpArguments\")\n    void SHR(Type type, int stackType, Object left, Object right) {\n        instance.visitLdcInsn(left);\n        instance.visitLdcInsn(right);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackType, type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        instance.visitInsn(type.getOpcode(Opcodes.ISHR));\n        i = instance.introspect();\n        assertEquals(type.getSize(), i.stack.size());\n        Object slotType = type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackType, slotType);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"bitwiseOpArguments\")\n    void SHL(Type type, int stackType, Object left, Object right) {\n        instance.visitLdcInsn(left);\n        instance.visitLdcInsn(right);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackType, type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        instance.visitInsn(type.getOpcode(Opcodes.ISHL));\n        i = instance.introspect();\n        assertEquals(type.getSize(), i.stack.size());\n        Object slotType = type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackType, slotType);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"bitwiseOpArguments\")\n    void USHR(Type type, int stackType, Object left, Object right) {\n        instance.visitLdcInsn(left);\n        instance.visitLdcInsn(right);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackType, type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        instance.visitInsn(type.getOpcode(Opcodes.IUSHR));\n        i = instance.introspect();\n        assertEquals(type.getSize(), i.stack.size());\n        Object slotType = type.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackType, slotType);\n    }\n\n    private static Stream<Arguments> arithmeticOpArguments() {\n        return Stream.of(\n                Arguments.of(Type.BYTE_TYPE, Opcodes.INTEGER, (byte)1, (byte)2),\n                Arguments.of(Type.CHAR_TYPE, Opcodes.INTEGER, (char)1, (char)2),\n                Arguments.of(Type.SHORT_TYPE, Opcodes.INTEGER, (short)1, (short)2),\n                Arguments.of(Type.INT_TYPE, Opcodes.INTEGER, 1, 2),\n                Arguments.of(Type.FLOAT_TYPE, Opcodes.FLOAT, 1f, 2f),\n                Arguments.of(Type.LONG_TYPE, Opcodes.LONG, 1L, 2L),\n                Arguments.of(Type.DOUBLE_TYPE, Opcodes.DOUBLE, 1d, 2d)\n        );\n    }\n\n    private static Stream<Arguments> bitwiseOpArguments() {\n        return Stream.of(\n                Arguments.of(Type.BYTE_TYPE, Opcodes.INTEGER, (byte)1, (byte)2),\n                Arguments.of(Type.CHAR_TYPE, Opcodes.INTEGER, (char)1, (char)2),\n                Arguments.of(Type.SHORT_TYPE, Opcodes.INTEGER, (short)1, (short)2),\n                Arguments.of(Type.INT_TYPE, Opcodes.INTEGER, 1, 2),\n                Arguments.of(Type.LONG_TYPE, Opcodes.LONG, 1L, 2L)\n        );\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"numCastArguments\")\n    void NUMCAST(Type from, Type to, Object value, int stackTypeFrom, int stackTypeTo) {\n        instance.visitLdcInsn(value);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(stackTypeFrom, from.getSize() == 2 ? i.stack.peekX1() : i.stack.peek());\n\n        int opcode = -1;\n        switch (from.getSort()) {\n            case Type.INT: {\n                switch (to.getSort()) {\n                    case Type.BYTE: opcode = Opcodes.I2B; break;\n                    case Type.CHAR: opcode = Opcodes.I2C; break;\n                    case Type.SHORT: opcode = Opcodes.I2S; break;\n                    case Type.FLOAT: opcode = Opcodes.I2F; break;\n                    case Type.LONG: opcode = Opcodes.I2L; break;\n                    case Type.DOUBLE: opcode = Opcodes.I2D; break;\n                }\n                break;\n            }\n            case Type.FLOAT: {\n                switch (to.getSort()) {\n                    case Type.INT: opcode = Opcodes.F2I; break;\n                    case Type.LONG: opcode = Opcodes.F2L; break;\n                    case Type.DOUBLE: opcode = Opcodes.F2D; break;\n                }\n                break;\n            }\n            case Type.LONG: {\n                switch (to.getSort()) {\n                    case Type.INT: opcode = Opcodes.L2I; break;\n                    case Type.FLOAT: opcode = Opcodes.L2F; break;\n                    case Type.DOUBLE: opcode = Opcodes.L2D; break;\n                }\n                break;\n            }\n            case Type.DOUBLE: {\n                switch (to.getSort()) {\n                    case Type.INT: opcode = Opcodes.D2I; break;\n                    case Type.LONG: opcode = Opcodes.D2L; break;\n                    case Type.FLOAT: opcode = Opcodes.D2F; break;\n                }\n                break;\n            }\n        }\n        assertNotEquals(-1, opcode);\n        instance.visitInsn(opcode);\n        i = instance.introspect();\n        assertEquals(to.getSize(), i.stack.size());\n        Object slotType = to.getSize() == 2 ? i.stack.peekX1() : i.stack.peek();\n        assertEquals(stackTypeTo, slotType);\n    }\n\n    private static Stream<Arguments> numCastArguments() {\n        return Stream.of(\n                Arguments.of(Type.INT_TYPE, Type.BYTE_TYPE, 1, Opcodes.INTEGER, Opcodes.INTEGER),\n                Arguments.of(Type.INT_TYPE, Type.CHAR_TYPE, 1, Opcodes.INTEGER, Opcodes.INTEGER),\n                Arguments.of(Type.INT_TYPE, Type.SHORT_TYPE, 1, Opcodes.INTEGER, Opcodes.INTEGER),\n                Arguments.of(Type.INT_TYPE, Type.FLOAT_TYPE, 1, Opcodes.INTEGER, Opcodes.FLOAT),\n                Arguments.of(Type.INT_TYPE, Type.LONG_TYPE, 1, Opcodes.INTEGER, Opcodes.LONG),\n                Arguments.of(Type.INT_TYPE, Type.DOUBLE_TYPE, 1, Opcodes.INTEGER, Opcodes.DOUBLE),\n                Arguments.of(Type.FLOAT_TYPE, Type.INT_TYPE, 1f, Opcodes.FLOAT, Opcodes.INTEGER),\n                Arguments.of(Type.FLOAT_TYPE, Type.LONG_TYPE, 1f, Opcodes.FLOAT, Opcodes.LONG),\n                Arguments.of(Type.FLOAT_TYPE, Type.DOUBLE_TYPE, 1f, Opcodes.FLOAT, Opcodes.DOUBLE),\n                Arguments.of(Type.DOUBLE_TYPE, Type.INT_TYPE, 1d, Opcodes.DOUBLE, Opcodes.INTEGER),\n                Arguments.of(Type.DOUBLE_TYPE, Type.LONG_TYPE, 1d, Opcodes.DOUBLE, Opcodes.LONG),\n                Arguments.of(Type.DOUBLE_TYPE, Type.FLOAT_TYPE, 1d, Opcodes.DOUBLE, Opcodes.FLOAT),\n                Arguments.of(Type.LONG_TYPE, Type.INT_TYPE, 1L, Opcodes.LONG, Opcodes.INTEGER),\n                Arguments.of(Type.LONG_TYPE, Type.DOUBLE_TYPE, 1L, Opcodes.LONG, Opcodes.DOUBLE),\n                Arguments.of(Type.LONG_TYPE, Type.FLOAT_TYPE, 1L, Opcodes.LONG, Opcodes.FLOAT)\n        );\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"cmpArguments\")\n    void CMP(int opcode, Object val) {\n        instance.visitLdcInsn(val);\n        instance.visitLdcInsn(val);\n\n        instance.visitInsn(opcode);\n\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n        assertEquals(1, i.stack.size());\n        assertEquals(Opcodes.INTEGER, i.stack.peek());\n    }\n\n    private static Stream<Arguments> cmpArguments() {\n        return Stream.of(\n                Arguments.of(Opcodes.LCMP, 1L),\n                Arguments.of(Opcodes.DCMPG, 1d),\n                Arguments.of(Opcodes.DCMPL, 1d),\n                Arguments.of(Opcodes.FCMPG, 1f),\n                Arguments.of(Opcodes.FCMPL, 1f)\n        );\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"retArguments\")\n    void RET(Type type, Object value) {\n        instance.visitLdcInsn(value);\n\n        instance.visitInsn(type.getOpcode(Opcodes.IRETURN));\n\n        assertEquals(0, instance.introspect().stack.size());\n    }\n\n    private static Stream<Arguments> retArguments() {\n        return Stream.of(\n                Arguments.of(Type.BYTE_TYPE, (byte)1),\n                Arguments.of(Type.CHAR_TYPE, (char)1),\n                Arguments.of(Type.SHORT_TYPE, (short)1),\n                Arguments.of(Type.INT_TYPE, 1),\n                Arguments.of(Type.FLOAT_TYPE, 1f),\n                Arguments.of(Type.DOUBLE_TYPE, 1d),\n                Arguments.of(Type.LONG_TYPE, 1L),\n                Arguments.of(Type.getType(String.class), \"hello\")\n        );\n    }\n\n    @Test\n    void THROW() {\n        instance.visitTypeInsn(Opcodes.NEW, Type.getDescriptor(RuntimeException.class));\n        instance.visitInsn(Opcodes.ATHROW);\n\n        assertEquals(0, instance.introspect().stack.size());\n    }\n\n    @Test\n    void ARRAYLENGTH() {\n        instance.visitLdcInsn(10); // load array size\n        instance.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_INT); // instantiate new array\n\n        instance.visitInsn(Opcodes.ARRAYLENGTH);\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n\n        assertEquals(1, i.stack.size());\n        assertEquals(Opcodes.INTEGER, i.stack.peek());\n    }\n\n    @Test\n    void MONITORENTER() {\n        instance.visitTypeInsn(Opcodes.NEW, Type.getDescriptor(Object.class));\n        instance.visitInsn(Opcodes.MONITORENTER);\n\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n\n        assertEquals(0, i.stack.size());\n    }\n\n    @Test\n    void MONITOREXIT() {\n        instance.visitTypeInsn(Opcodes.NEW, Type.getDescriptor(Object.class));\n        instance.visitInsn(Opcodes.MONITOREXIT);\n\n        InstrumentingMethodVisitor.Introspection i = instance.introspect();\n\n        assertEquals(0, i.stack.size());\n    }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/InstrumentUtilsTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport java.util.stream.Stream;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\nimport org.objectweb.asm.Type;\n\npublic class InstrumentUtilsTest {\n  @ParameterizedTest(name = \"Left: {0}, Right: {1}, Exact match: {2}, Assignable: {3}\")\n  @MethodSource(\"signaturesArguments\")\n  void testIsAssignableSignature(\n      Type[] left, Type[] right, boolean exactMatch, boolean isAssignable) {\n    assertEquals(isAssignable, InstrumentUtils.isAssignable(left, right, null, exactMatch));\n  }\n\n  @ParameterizedTest(name = \"Left: {0}, Right: {1}, Exact match: {2}, Assignable: {3}\")\n  @MethodSource(\"typeAssignments\")\n  void testAssignableTypes(Type left, Type right, boolean exactMatch, boolean isAssignable) {\n    assertEquals(isAssignable, InstrumentUtils.isAssignable(left, right, null, exactMatch));\n  }\n\n  private static Stream<Arguments> typeAssignments() {\n    return Stream.of(\n        Arguments.of(Type.INT_TYPE, Type.INT_TYPE, false, true),\n        Arguments.of(Type.INT_TYPE, Type.INT_TYPE, true, true),\n        Arguments.of(Type.INT_TYPE, Type.LONG_TYPE, false, false),\n        Arguments.of(Type.INT_TYPE, Type.LONG_TYPE, true, false),\n        Arguments.of(Type.getType(Object.class), Type.getType(Object.class), false, true),\n        Arguments.of(Type.getType(Object.class), Type.getType(Object.class), true, true),\n        Arguments.of(Type.getType(Object.class), Type.getType(String.class), false, true),\n        Arguments.of(Type.getType(Object.class), Type.getType(String.class), true, false),\n        Arguments.of(Constants.ANYTYPE_TYPE, Type.getType(Object.class), false, true),\n        Arguments.of(Constants.ANYTYPE_TYPE, Type.getType(Object.class), true, true),\n        Arguments.of(Constants.ANYTYPE_TYPE, Type.getType(String.class), false, true),\n        Arguments.of(Constants.ANYTYPE_TYPE, Type.getType(String.class), true, true),\n        Arguments.of(Constants.ANYTYPE_TYPE, Type.getType(String[].class), false, true),\n        Arguments.of(Constants.ANYTYPE_TYPE, Type.getType(String[].class), true, true),\n        Arguments.of(Constants.ANYTYPE_TYPE, Type.INT_TYPE, false, true),\n        Arguments.of(Constants.ANYTYPE_TYPE, Type.INT_TYPE, true, true));\n  }\n\n  private static Stream<Arguments> signaturesArguments() {\n    return Stream.of(\n        Arguments.of(\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE},\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE},\n            true,\n            true),\n        Arguments.of(\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE},\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE},\n            false,\n            true),\n        Arguments.of(\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE},\n            new Type[] {Type.getType(String.class), Type.INT_TYPE},\n            true,\n            false),\n        Arguments.of(\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE},\n            new Type[] {Type.getType(String.class), Type.INT_TYPE},\n            false,\n            true),\n        Arguments.of(\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE},\n            new Type[] {Type.getType(Object.class), Type.getType(String.class)},\n            true,\n            false),\n        Arguments.of(\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE},\n            new Type[] {Type.getType(Object.class), Type.getType(String.class)},\n            false,\n            false),\n        Arguments.of(\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE},\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE, Type.getType(Object.class)},\n            true,\n            false),\n        Arguments.of(\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE},\n            new Type[] {Type.getType(Object.class), Type.INT_TYPE, Type.getType(Object.class)},\n            false,\n            false));\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/InstrumentingMethodVisitorTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.Arrays;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Random;\nimport java.util.Set;\nimport java.util.stream.Stream;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\nimport org.junit.jupiter.params.provider.ValueSource;\nimport org.objectweb.asm.ClassWriter;\nimport org.objectweb.asm.Handle;\nimport org.objectweb.asm.Label;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.Type;\n\npublic class InstrumentingMethodVisitorTest {\n  private static final class LastVisitedFrame {\n    final int type;\n    final int nLocal;\n    final Object[] local;\n    final int nStack;\n    final Object[] stack;\n\n    public LastVisitedFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {\n      this.type = type;\n      this.nLocal = nLocal;\n      this.local = local != null ? Arrays.copyOf(local, nLocal) : null;\n      this.nStack = nStack;\n      this.stack = stack != null ? Arrays.copyOf(stack, nStack) : null;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n      if (this == o) return true;\n      if (o == null || getClass() != o.getClass()) return false;\n      LastVisitedFrame that = (LastVisitedFrame) o;\n      return type == that.type\n          && nLocal == that.nLocal\n          && nStack == that.nStack\n          && Arrays.equals(local, that.local)\n          && Arrays.equals(stack, that.stack);\n    }\n\n    @Override\n    public int hashCode() {\n      int result = Objects.hash(type, nLocal, nStack);\n      result = 31 * result + Arrays.hashCode(local);\n      result = 31 * result + Arrays.hashCode(stack);\n      return result;\n    }\n\n    @Override\n    public String toString() {\n      return \"LastVisitedFrame{\"\n          + \"type=\"\n          + type\n          + \", nLocal=\"\n          + nLocal\n          + \", local=\"\n          + Arrays.toString(local)\n          + \", nStack=\"\n          + nStack\n          + \", stack=\"\n          + Arrays.toString(stack)\n          + '}';\n    }\n  }\n\n  private InstrumentingMethodVisitor instance;\n  private LastVisitedFrame lastVisitedFrame = null;\n\n  @BeforeEach\n  void setup() throws Exception {\n    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);\n    cw.visit(Opcodes.ASM9, Opcodes.ACC_PUBLIC, \"test.Test\", null, null, null);\n    MethodVisitor mv =\n        cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, \"test\", \"()V\", null, null);\n    instance =\n        new InstrumentingMethodVisitor(\n            Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,\n            \"test.Test\",\n            \"test\",\n            \"()V\",\n            mv,\n            (type, nLocal, local, nStack, stack) -> {\n              lastVisitedFrame = new LastVisitedFrame(type, nLocal, local, nStack, stack);\n            });\n  }\n\n  @AfterEach\n  void teardown() {\n    lastVisitedFrame = null;\n  }\n\n  @Test\n  public void testComplexSparkContextInit() {\n    Object[] expected = {\n      \"org/apache/spark/SparkContext\",\n      \"org/apache/spark/SparkConf\",\n      \"java/util/concurrent/ConcurrentMap\",\n      \"scala/Option\",\n      \"java/lang/String\",\n      0,\n      0,\n      1,\n      \"scala/Option\",\n      \"scala/Tuple2\",\n      \"org/apache/spark/scheduler/SchedulerBackend\",\n      \"org/apache/spark/scheduler/TaskScheduler\",\n      \"scala/Tuple2\",\n      \"scala/Tuple2\",\n      \"org/apache/spark/scheduler/SchedulerBackend\",\n      \"org/apache/spark/scheduler/TaskScheduler\",\n      \"scala/Option\",\n      0,\n      1,\n      \"org/apache/spark/scheduler/SchedulerBackend\",\n      \"scala/Option\"\n    };\n    VariableMapper mapper =\n        new VariableMapper(\n            2,\n            21,\n            new int[] {\n              0,\n              0,\n              -2147483628,\n              -2147483636,\n              -2147483646,\n              -2147483645,\n              -2147483644,\n              -2147483643,\n              -2147483642,\n              -2147483641,\n              -2147483640,\n              -2147483635,\n              -2147483639,\n              -2147483638,\n              -2147483637,\n              -2147483634,\n              -2147483633,\n              -2147483632,\n              -2147483631,\n              -2147483630,\n              -2147483629,\n              0,\n              0,\n              0,\n              0,\n              0,\n              0,\n              0,\n              0,\n              0,\n              0,\n              0\n            });\n\n    Object[] fromFrame = {\n      \"org/apache/spark/SparkContext\",\n      \"org/apache/spark/SparkConf\",\n      0,\n      0,\n      \"scala/Option\",\n      \"scala/Tuple2\",\n      \"java/util/concurrent/ConcurrentMap\",\n      \"scala/Option\",\n      \"java/lang/String\",\n      0,\n      0,\n      1,\n      \"scala/Option\",\n      \"scala/Tuple2\",\n      \"scala/Tuple2\",\n      \"org/apache/spark/scheduler/SchedulerBackend\",\n      \"org/apache/spark/scheduler/TaskScheduler\",\n      \"org/apache/spark/scheduler/SchedulerBackend\",\n      \"org/apache/spark/scheduler/TaskScheduler\",\n      \"scala/Option\",\n      0,\n      1,\n      \"org/apache/spark/scheduler/SchedulerBackend\"\n    };\n    Object[] locals =\n        InstrumentingMethodVisitor.computeFrameLocals(2, Arrays.asList(fromFrame), null, mapper);\n    assertArrayEquals(expected, locals);\n  }\n\n  @Test\n  void multiArrayLoad() {\n    String expected1 = \"[[[Ljava/lang/String;\";\n    String expected2 = \"[[Ljava/lang/String;\";\n    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);\n    cw.visit(Opcodes.ASM9, Opcodes.ACC_PUBLIC, \"test.Test\", null, null, null);\n    MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, \"test\", \"()V\", null, null);\n    InstrumentingMethodVisitor instance = new InstrumentingMethodVisitor(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, \"test.Test\", \"test\", \"()V\", mv);\n    mv = instance;\n\n    mv.visitLdcInsn(1);\n    mv.visitLdcInsn(1);\n    mv.visitLdcInsn(1);\n    mv.visitMultiANewArrayInsn(\"[[[Ljava/lang/String;\", 3);\n    assertEquals(expected1, instance.introspect().stack.peek());\n\n    mv.visitLdcInsn(0);\n    mv.visitInsn(Opcodes.AALOAD);\n    assertEquals(expected2, instance.introspect().stack.peek());\n\n    mv.visitMaxs(3, 0);\n    mv.visitEnd();\n\n  }\n\n  @Test\n  void computeFrameLocalsFuzz() {\n    long seed = Long.getLong(\"btrace.test.seed\", 0x5EED5EEDL);\n    Random random = new Random(seed);\n    for (int i = 0; i < 500; i++) {\n      int slotCount = 1 + random.nextInt(30);\n      List<Object> locals = buildLocals(random, slotCount);\n      int argsSize = random.nextInt(Math.min(slotCount + 1, 6));\n      VariableMapper mapper = new VariableMapper(argsSize);\n\n      int remapOps = random.nextInt(10);\n      for (int r = 0; r < remapOps; r++) {\n        int idx = random.nextInt(slotCount);\n        int size = random.nextBoolean() ? 1 : 2;\n        mapper.remap(idx, size);\n      }\n      int newVars = random.nextInt(5);\n      for (int n = 0; n < newVars; n++) {\n        mapper.newVarIdx(random.nextBoolean() ? 1 : 2);\n      }\n\n      Set<InstrumentingMethodVisitor.LocalVarSlot> newLocals = new HashSet<>();\n      int newLocalCount = random.nextInt(6);\n      for (int n = 0; n < newLocalCount; n++) {\n        int idx = random.nextInt(slotCount + 6);\n        Object type = randomSlotType(random);\n        InstrumentingMethodVisitor.LocalVarSlot slot =\n            new InstrumentingMethodVisitor.LocalVarSlot(idx, type);\n        if (random.nextBoolean()) {\n          slot.expire();\n        }\n        newLocals.add(slot);\n      }\n\n      Object[] result =\n          InstrumentingMethodVisitor.computeFrameLocals(argsSize, locals, newLocals, mapper);\n      assertNotNull(result);\n      for (int p = 0; p < result.length; p++) {\n        Object val = result[p];\n        assertNotNull(val, \"null local at index \" + p);\n        if (val == InstrumentingMethodVisitor.TOP_EXT) {\n          assertTrue(p > 0, \"TOP_EXT at index 0\");\n          Object prev = result[p - 1];\n          assertTrue(prev == Opcodes.LONG || prev == Opcodes.DOUBLE, \"TOP_EXT without LONG/DOUBLE\");\n        }\n        if (val == Opcodes.LONG || val == Opcodes.DOUBLE) {\n          assertTrue(p + 1 < result.length, \"LONG/DOUBLE without TOP_EXT\");\n          assertEquals(\n              InstrumentingMethodVisitor.TOP_EXT,\n              result[p + 1],\n              \"LONG/DOUBLE missing TOP_EXT\");\n        }\n      }\n    }\n  }\n\n  private static List<Object> buildLocals(Random random, int slotCount) {\n    List<Object> locals = new ArrayList<>(slotCount);\n    int slots = 0;\n    while (slots < slotCount) {\n      int remaining = slotCount - slots;\n      Object type = randomSlotType(random);\n      if ((type == Opcodes.LONG || type == Opcodes.DOUBLE) && remaining >= 2) {\n        locals.add(type);\n        locals.add(Opcodes.TOP);\n        slots += 2;\n      } else if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {\n        locals.add(Opcodes.INTEGER);\n        slots += 1;\n      } else {\n        locals.add(type);\n        slots += 1;\n      }\n    }\n    return locals;\n  }\n\n  private static Object randomSlotType(Random random) {\n    int pick = random.nextInt(6);\n    switch (pick) {\n      case 0:\n        return Opcodes.INTEGER;\n      case 1:\n        return Opcodes.FLOAT;\n      case 2:\n        return Opcodes.LONG;\n      case 3:\n        return Opcodes.DOUBLE;\n      case 4:\n        return Opcodes.TOP;\n      default:\n        return \"java/lang/Object\";\n    }\n  }\n\n  @Test\n  void computeFrameLocalsCompactLongThenRef() {\n    // Reproduces FutureTask.get(long, TimeUnit): compact locals [owner, LONG, TimeUnit]\n    // with no variable remapping (nextMappedVar == argsSize) triggers the else branch.\n    // The else branch must expand LONG to [LONG, TOP_EXT] to avoid overwriting TimeUnit.\n    int argsSize = 4; // this(1) + long(2) + ref(1)\n    List<Object> locals =\n        Arrays.asList(\n            \"java/util/concurrent/FutureTask\",\n            Opcodes.LONG,\n            \"java/util/concurrent/TimeUnit\");\n    VariableMapper mapper = new VariableMapper(argsSize);\n\n    Object[] result =\n        InstrumentingMethodVisitor.computeFrameLocals(argsSize, locals, null, mapper);\n\n    Object[] expected = {\n      \"java/util/concurrent/FutureTask\",\n      Opcodes.LONG,\n      InstrumentingMethodVisitor.TOP_EXT,\n      \"java/util/concurrent/TimeUnit\"\n    };\n    assertArrayEquals(expected, result);\n  }\n\n  @ParameterizedTest\n  @MethodSource(\"typeValues\")\n  void storeAsNew(Object value, Type type) {\n    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);\n    cw.visit(Opcodes.ASM9, Opcodes.ACC_PUBLIC, \"test.Test\", null, null, null);\n    MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, \"test\", \"()V\", null, null);\n    InstrumentingMethodVisitor instance = new InstrumentingMethodVisitor(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, \"test.Test\", \"test\", \"()V\", mv);\n    mv = instance;\n\n    mv.visitLdcInsn(value);\n    Object expected = instance.introspect().stack.peek();\n    int idx = instance.storeAsNew();\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.newLocals.size());\n    assertEquals(0, i.stack.size());\n    instance.visitVarInsn(type.getOpcode(Opcodes.ILOAD), idx);\n    assertEquals(expected, instance.introspect().stack.peek());\n  }\n\n  private static Stream<Arguments> typeValues() {\n    return Stream.of(\n            Arguments.of((byte)1, Type.BYTE_TYPE),\n            Arguments.of((short)1, Type.SHORT_TYPE),\n            Arguments.of((char)1, Type.CHAR_TYPE),\n            Arguments.of((int)1, Type.INT_TYPE),\n            Arguments.of(true, Type.BOOLEAN_TYPE),\n            Arguments.of((long)1, Type.LONG_TYPE),\n            Arguments.of((float)1, Type.FLOAT_TYPE),\n            Arguments.of((double)1, Type.DOUBLE_TYPE)\n    );\n  }\n\n  @Test\n  void ACONST_NULL() {\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    assertEquals(Opcodes.NULL, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void ICONST_1() {\n    instance.visitInsn(Opcodes.ICONST_1);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void ICONST_2() {\n    instance.visitInsn(Opcodes.ICONST_2);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void ICONST_3() {\n    instance.visitInsn(Opcodes.ICONST_3);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void ICONST_4() {\n    instance.visitInsn(Opcodes.ICONST_4);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void ICONST_5() {\n    instance.visitInsn(Opcodes.ICONST_5);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void ICONST_M1() {\n    instance.visitInsn(Opcodes.ICONST_M1);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void FCONST_0() {\n    instance.visitInsn(Opcodes.FCONST_0);\n    assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void FCONST_1() {\n    instance.visitInsn(Opcodes.FCONST_1);\n    assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void FCONST_2() {\n    instance.visitInsn(Opcodes.FCONST_2);\n    assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void DCONST_0() {\n    instance.visitInsn(Opcodes.DCONST_0);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.DOUBLE, i.stack.peekX1());\n  }\n\n  @Test\n  void DCONST_1() {\n    instance.visitInsn(Opcodes.DCONST_1);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.DOUBLE, i.stack.peekX1());\n  }\n\n  @Test\n  void LCONST_0() {\n    instance.visitInsn(Opcodes.LCONST_0);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.LONG, i.stack.peekX1());\n  }\n\n  @Test\n  void LCONST_1() {\n    instance.visitInsn(Opcodes.LCONST_1);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.LONG, i.stack.peekX1());\n  }\n\n  @Test\n  void AALOAD() {\n    instance.visitLdcInsn(1);\n    instance.visitTypeInsn(Opcodes.ANEWARRAY, \"java/lang/String\");\n    assertEquals(\"[Ljava/lang/String;\", instance.introspect().stack.peek());\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.AALOAD);\n    assertEquals(\"java/lang/String\", instance.introspect().stack.peek());\n  }\n\n  @Test\n  void AALOAD_TYPEDESC() {\n    instance.visitLdcInsn(1);\n    instance.visitTypeInsn(Opcodes.ANEWARRAY, \"Ljava/lang/String;\");\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.AALOAD);\n    assertEquals(\"java/lang/String\", instance.introspect().stack.peek());\n  }\n\n  @Test\n  void AALOAD_NULL() {\n    instance.visitLdcInsn(1);\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.AALOAD);\n    assertEquals(Opcodes.NULL, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void AALOAD_INVALID() {\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.AALOAD);\n    assertEquals(\"java/lang/Object\", instance.introspect().stack.peek());\n  }\n\n  @Test\n  void IALOAD() {\n    instance.visitLdcInsn(1);\n    instance.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_INT);\n    assertEquals(\"[I\", instance.introspect().stack.peek());\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.IALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void IALOAD_NULL() {\n    instance.visitLdcInsn(1);\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.IALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void IALOAD_INVALID() {\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.IALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void FALOAD() {\n    instance.visitLdcInsn(1);\n    instance.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_FLOAT);\n    assertEquals(\"[F\", instance.introspect().stack.peek());\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.FALOAD);\n    assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void FALOAD_NULL() {\n    instance.visitLdcInsn(1);\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.FALOAD);\n    assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void FALOAD_INVALID() {\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.FALOAD);\n    assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void BALOAD() {\n    instance.visitLdcInsn(1);\n    instance.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BYTE);\n    assertEquals(\"[B\", instance.introspect().stack.peek());\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.BALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void BALOAD_NULL() {\n    instance.visitLdcInsn(1);\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.BALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void BALOAD_INVALID() {\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.BALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void CALOAD() {\n    instance.visitLdcInsn(1);\n    instance.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_CHAR);\n    assertEquals(\"[C\", instance.introspect().stack.peek());\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.CALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void CALOAD_NULL() {\n    instance.visitLdcInsn(1);\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.CALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void CALOAD_INVALID() {\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.CALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void SALOAD() {\n    instance.visitLdcInsn(1);\n    instance.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_SHORT);\n    assertEquals(\"[S\", instance.introspect().stack.peek());\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.SALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void SALOAD_NULL() {\n    instance.visitLdcInsn(1);\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.SALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void SALOAD_INVALID() {\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.SALOAD);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void LALOAD() {\n    instance.visitLdcInsn(1);\n    instance.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_LONG);\n    assertEquals(\"[J\", instance.introspect().stack.peek());\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.LALOAD);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.LONG, i.stack.peekX1());\n  }\n\n  @Test\n  void LALOAD_NULL() {\n    instance.visitLdcInsn(1);\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.LALOAD);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.LONG, i.stack.peekX1());\n  }\n\n  @Test\n  void LALOAD_INVALID() {\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.LALOAD);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.LONG, i.stack.peekX1());\n  }\n\n  @Test\n  void DALOAD() {\n    instance.visitLdcInsn(1);\n    instance.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_DOUBLE);\n    assertEquals(\"[D\", instance.introspect().stack.peek());\n\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.DALOAD);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.DOUBLE, i.stack.peekX1());\n  }\n\n  @Test\n  void DALOAD_NULL() {\n    instance.visitLdcInsn(1);\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.DALOAD);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.DOUBLE, i.stack.peekX1());\n  }\n\n  @Test\n  void DALOAD_INVALID() {\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.DALOAD);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.DOUBLE, i.stack.peekX1());\n  }\n\n  @Test\n  void AASTORE() {\n    instance.visitLdcInsn(1);\n    instance.visitTypeInsn(Opcodes.ANEWARRAY, \"java/lang/String\"); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(\"hello\"); // value\n    instance.visitInsn(Opcodes.AASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void AASTORE_TYPEDESC() {\n    instance.visitLdcInsn(1);\n    instance.visitTypeInsn(Opcodes.ANEWARRAY, \"Ljava/lang/String;\"); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(\"hello\"); // value\n    instance.visitInsn(Opcodes.AASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void AASTORE_NULL() {\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(\"hello\"); // value\n    instance.visitInsn(Opcodes.AASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void AASTORE_INVALID() {\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(\"hello\"); // value\n    instance.visitInsn(Opcodes.AASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void IASTORE() {\n    instance.visitLdcInsn(1);\n    instance.visitTypeInsn(Opcodes.ANEWARRAY, \"I\"); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.IASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void IASTORE_NULL() {\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.IASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void IASTORE_INVALID() {\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.IASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void BASTORE() {\n    instance.visitLdcInsn(1);\n    instance.visitTypeInsn(Opcodes.ANEWARRAY, \"B\"); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.BASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void BASTORE_NULL() {\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.BASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void BASTORE_INVALID() {\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.BASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void CASTORE() {\n    instance.visitLdcInsn(1);\n    instance.visitTypeInsn(Opcodes.ANEWARRAY, \"C\"); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.CASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void CASTORE_NULL() {\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.CASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void CASTORE_INVALID() {\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.CASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void SASTORE() {\n    instance.visitLdcInsn(1);\n    instance.visitTypeInsn(Opcodes.ANEWARRAY, \"S\"); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.SASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void SASTORE_NULL() {\n    instance.visitInsn(Opcodes.ACONST_NULL);\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.SASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void SASTORE_INVALID() {\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.SASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void FASTORE() {\n    instance.visitLdcInsn(1);\n    instance.visitTypeInsn(Opcodes.ANEWARRAY, \"F\"); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1f); // value\n    instance.visitInsn(Opcodes.FASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void FASTORE_NULL() {\n    instance.visitInsn(Opcodes.ACONST_NULL); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1f); // value\n    instance.visitInsn(Opcodes.FASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void FASTORE_INVALID() {\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1f); // value\n    instance.visitInsn(Opcodes.FASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void LASTORE() {\n    instance.visitLdcInsn(1);\n    instance.visitTypeInsn(Opcodes.ANEWARRAY, \"J\"); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1L); // value\n    instance.visitInsn(Opcodes.LASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void LASTORE_NULL() {\n    instance.visitInsn(Opcodes.ACONST_NULL); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1L); // value\n    instance.visitInsn(Opcodes.LASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void LASTORE_INVALID() {\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.LASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void DASTORE() {\n    instance.visitLdcInsn(1);\n    instance.visitTypeInsn(Opcodes.ANEWARRAY, \"D\"); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1d); // value\n    instance.visitInsn(Opcodes.DASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void DASTORE_NULL() {\n    instance.visitInsn(Opcodes.ACONST_NULL); // arrayref\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1d); // value\n    instance.visitInsn(Opcodes.DASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void DASTORE_INVALID() {\n    instance.visitLdcInsn(0); // index\n    instance.visitLdcInsn(1); // value\n    instance.visitInsn(Opcodes.DASTORE);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void POP() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitInsn(Opcodes.POP);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.POP);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.POP);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void POP2() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(2);\n    instance.visitInsn(Opcodes.POP2);\n    assertEquals(Opcodes.TOP, instance.introspect().stack.peek());\n\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(2L);\n    instance.visitInsn(Opcodes.POP2);\n    assertEquals(Opcodes.INTEGER, instance.introspect().stack.peek());\n  }\n\n  @Test\n  void DUP() {\n    instance.visitLdcInsn(1);\n    instance.visitInsn(Opcodes.DUP);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n\n    assertEquals(2, i.stack.size());\n    assertEquals(Opcodes.INTEGER, i.stack.peek());\n  }\n\n  @Test\n  void DUP_X1() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitLdcInsn(2f);\n\n    assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.DUP_X1);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(4, i.stack.size());\n    assertEquals(Opcodes.FLOAT, i.stack.peek(2));\n  }\n\n  @Test\n  void DUP_X2() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitLdcInsn(2f);\n\n    assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.DUP_X2);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(4, i.stack.size());\n    assertEquals(Opcodes.FLOAT, i.stack.peek(3));\n  }\n\n  @Test\n  void DUP_X2_LONG() {\n    instance.visitLdcInsn(\"hello\");\n    instance.visitLdcInsn(1L);\n    instance.visitLdcInsn(2f);\n\n    assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.DUP_X2);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(5, i.stack.size());\n    assertEquals(Opcodes.FLOAT, i.stack.peek(3));\n  }\n\n  @Test\n  void DUP2() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(2f);\n    assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.DUP2);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(4, i.stack.size());\n    assertEquals(Opcodes.FLOAT, i.stack.peek());\n    assertEquals(Opcodes.INTEGER, i.stack.peek(1));\n  }\n\n  @Test\n  void DUP2_LONG() {\n    instance.visitLdcInsn(1L);\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.DUP2);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(4, i.stack.size());\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.LONG, i.stack.peek(1));\n  }\n\n  @Test\n  void DUP2_X1() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(2f);\n    instance.visitLdcInsn(\"hello\");\n\n    assertEquals(\"java/lang/String\", instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.DUP2_X1);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(5, i.stack.size());\n    assertEquals(\"java/lang/String\", i.stack.peek(3));\n    assertEquals(Opcodes.FLOAT, i.stack.peek(4));\n  }\n\n  @Test\n  void DUP2_X1_LONG() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(2L);\n\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.DUP2_X1);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(5, i.stack.size());\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek(3));\n    assertEquals(Opcodes.LONG, i.stack.peek(4));\n  }\n\n  @Test\n  void DUP2_X2() {\n    instance.visitLdcInsn(0);\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(2f);\n    instance.visitLdcInsn(\"hello\");\n\n    assertEquals(\"java/lang/String\", instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.DUP2_X2);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(6, i.stack.size());\n    assertEquals(\"java/lang/String\", i.stack.peek(4));\n    assertEquals(Opcodes.FLOAT, i.stack.peek(5));\n  }\n\n  @Test\n  void DUP2_X2_LONG() {\n    instance.visitLdcInsn(0);\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(2L);\n\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.DUP2_X2);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(6, i.stack.size());\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek(4));\n    assertEquals(Opcodes.LONG, i.stack.peek(5));\n  }\n\n  @Test\n  void SWAP() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(2f);\n\n    assertEquals(Opcodes.FLOAT, instance.introspect().stack.peek());\n\n    instance.visitInsn(Opcodes.SWAP);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(Opcodes.INTEGER, i.stack.peek());\n    assertEquals(Opcodes.FLOAT, i.stack.peek(1));\n  }\n\n  @ParameterizedTest\n  @ValueSource(\n      ints = {\n        Opcodes.IADD, Opcodes.ISUB, Opcodes.IMUL, Opcodes.IDIV, Opcodes.IREM,\n        Opcodes.IOR, Opcodes.IXOR, Opcodes.ISHR, Opcodes.ISHL, Opcodes.IUSHR\n      })\n  void I_binary_ops(int opcode) {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(2);\n    instance.visitInsn(opcode);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.stack.size());\n    assertEquals(Opcodes.INTEGER, i.stack.peek());\n  }\n\n  @ParameterizedTest\n  @ValueSource(\n      ints = {\n        Opcodes.LADD, Opcodes.LSUB, Opcodes.LMUL, Opcodes.LDIV, Opcodes.LREM,\n        Opcodes.LOR, Opcodes.LXOR, Opcodes.LSHR, Opcodes.LSHL, Opcodes.LUSHR\n      })\n  void L_binary_ops(int opcode) {\n    instance.visitLdcInsn(1L);\n    instance.visitLdcInsn(2L);\n    instance.visitInsn(opcode);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.LONG, i.stack.peek(1));\n  }\n\n  @ParameterizedTest\n  @ValueSource(ints = {Opcodes.FADD, Opcodes.FSUB, Opcodes.FMUL, Opcodes.FDIV, Opcodes.FREM})\n  void F_binary_ops(int opcode) {\n    instance.visitLdcInsn(1f);\n    instance.visitLdcInsn(2f);\n    instance.visitInsn(opcode);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.stack.size());\n    assertEquals(Opcodes.FLOAT, i.stack.peek());\n  }\n\n  @ParameterizedTest\n  @ValueSource(ints = {Opcodes.DADD, Opcodes.DSUB, Opcodes.DMUL, Opcodes.DDIV, Opcodes.DREM})\n  void D_binary_ops(int opcode) {\n    instance.visitLdcInsn(1d);\n    instance.visitLdcInsn(2d);\n    instance.visitInsn(opcode);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(InstrumentingMethodVisitor.TOP_EXT, i.stack.peek());\n    assertEquals(Opcodes.DOUBLE, i.stack.peek(1));\n  }\n\n  @ParameterizedTest\n  @ValueSource(\n      ints = {\n        Opcodes.I2B, Opcodes.I2C, Opcodes.I2D, Opcodes.I2F, Opcodes.I2L, Opcodes.I2S,\n        Opcodes.F2I, Opcodes.F2D, Opcodes.F2L, Opcodes.L2I, Opcodes.L2F, Opcodes.L2D,\n        Opcodes.D2I, Opcodes.D2F, Opcodes.D2L\n      })\n  void testConversion(int opcode) {\n    Object[] args = conversionTypes(opcode);\n\n    instance.visitLdcInsn(args[0]);\n    instance.visitInsn(opcode);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    int expectedStackSize = (int) args[1];\n    assertEquals(expectedStackSize, i.stack.size());\n    if (expectedStackSize == 1) {\n      assertEquals(args[2], i.stack.peek());\n    } else {\n      for (int p = 0; p < expectedStackSize; p++) {\n        assertEquals(((Object[]) args[2])[p], i.stack.peek(p));\n      }\n    }\n  }\n\n  @Test\n  void LCMP() {\n    instance.visitLdcInsn(1L);\n    instance.visitLdcInsn(2L);\n\n    instance.visitInsn(Opcodes.LCMP);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.stack.size());\n    assertEquals(Opcodes.INTEGER, i.stack.pop());\n  }\n\n  @ParameterizedTest\n  @ValueSource(ints = {Opcodes.FCMPG, Opcodes.FCMPL})\n  void FCMP(int opcode) {\n    instance.visitLdcInsn(1f);\n    instance.visitLdcInsn(2f);\n\n    instance.visitInsn(opcode);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.stack.size());\n    assertEquals(Opcodes.INTEGER, i.stack.pop());\n  }\n\n  @ParameterizedTest\n  @ValueSource(ints = {Opcodes.DCMPG, Opcodes.DCMPL})\n  void DCMP(int opcode) {\n    instance.visitLdcInsn(1d);\n    instance.visitLdcInsn(2d);\n\n    instance.visitInsn(opcode);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.stack.size());\n    assertEquals(Opcodes.INTEGER, i.stack.pop());\n  }\n\n  @ParameterizedTest\n  @ValueSource(\n      ints = {Opcodes.ARETURN, Opcodes.IRETURN, Opcodes.LRETURN, Opcodes.FRETURN, Opcodes.DRETURN})\n  void RET(int opcode) {\n    switch (opcode) {\n      case Opcodes.ARETURN:\n        instance.visitLdcInsn(\"hello\");\n        break;\n      case Opcodes.IRETURN:\n        instance.visitLdcInsn(1);\n        break;\n      case Opcodes.FRETURN:\n        instance.visitLdcInsn(1f);\n        break;\n      case Opcodes.LRETURN:\n        instance.visitLdcInsn(1L);\n        break;\n      case Opcodes.DRETURN:\n        instance.visitLdcInsn(1d);\n        break;\n      default:\n        throw new RuntimeException(\"Unexpected opcode: \" + opcode);\n    }\n    instance.visitInsn(opcode);\n\n    assertEquals(0, instance.introspect().stack.size());\n  }\n\n  @Test\n  void ATHROW() {\n    instance.visitTypeInsn(Opcodes.NEW, \"java/lang/RuntimeException\");\n\n    instance.visitInsn(Opcodes.ATHROW);\n    assertEquals(0, instance.introspect().stack.size());\n  }\n\n  @Test\n  void ARRAYLENGTH() {\n    instance.visitLdcInsn(1);\n    instance.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_INT);\n\n    instance.visitInsn(Opcodes.ARRAYLENGTH);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.stack.size());\n    assertEquals(Opcodes.INTEGER, i.stack.peek());\n  }\n\n  @ParameterizedTest\n  @ValueSource(ints = {Opcodes.MONITORENTER, Opcodes.MONITOREXIT})\n  void MONITOR(int opcode) {\n    instance.visitLdcInsn(\"this\");\n\n    instance.visitInsn(opcode);\n    assertEquals(0, instance.introspect().stack.size());\n  }\n\n  @ParameterizedTest\n  @ValueSource(ints = {Opcodes.BIPUSH, Opcodes.SIPUSH})\n  void PUSH(int opcode) {\n    instance.visitIntInsn(opcode, 0);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.stack.size());\n    assertEquals(Opcodes.INTEGER, i.stack.peek());\n  }\n\n  @Test\n  void INSTANCEOF() {\n    instance.visitLdcInsn(\"hello\");\n    instance.visitTypeInsn(Opcodes.INSTANCEOF, \"Ljava/util/List;\");\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.stack.size());\n    assertEquals(Opcodes.INTEGER, i.stack.peek());\n  }\n\n  @Test\n  void CHECKCAST() {\n    String expectedType = \"Ljava/util/List;\";\n    instance.visitLdcInsn(\"hello\");\n    instance.visitTypeInsn(Opcodes.CHECKCAST, expectedType);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.stack.size());\n    assertEquals(expectedType, i.stack.peek());\n  }\n\n  @ParameterizedTest\n  @ValueSource(ints = {Opcodes.ILOAD, Opcodes.FLOAD, Opcodes.LLOAD, Opcodes.DLOAD})\n  void VAR_LOAD(int opcode) {\n    instance.visitVarInsn(opcode, 1);\n\n    Object[] expected = {};\n    switch (opcode) {\n      case Opcodes.ILOAD:\n        expected = new Object[] {Opcodes.INTEGER};\n        break;\n      case Opcodes.FLOAD:\n        expected = new Object[] {Opcodes.FLOAT};\n        break;\n      case Opcodes.LLOAD:\n        expected = new Object[] {InstrumentingMethodVisitor.TOP_EXT, Opcodes.LONG};\n        break;\n      case Opcodes.DLOAD:\n        expected = new Object[] {InstrumentingMethodVisitor.TOP_EXT, Opcodes.DOUBLE};\n        break;\n    }\n    if (expected.length == 0) {\n      throw new RuntimeException(\"Unexpected opcode: \" + opcode);\n    }\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    for (int p = 0; p < expected.length; p++) {\n      assertEquals(\n          expected[p],\n          i.stack.peek(p),\n          \"Expected slot: \" + expected[p] + \", got \" + i.stack.peek(p));\n    }\n  }\n\n  @Test\n  void NEWARRAY_BOOLEAN() {\n    instance.visitLdcInsn(1);\n    instance.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BOOLEAN);\n\n    assertEquals(\"[Z\", instance.introspect().stack.peek());\n  }\n\n  @Test\n  void MULTIANEWARRAY() {\n    String expected1 = \"[[[Ljava/lang/String;\";\n    String expected2 = \"[[Ljava/lang/String;\";\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(1);\n    instance.visitMultiANewArrayInsn(\"[[[Ljava/lang/String;\", 3);\n    assertEquals(expected1, instance.introspect().stack.peek());\n\n    instance.visitLdcInsn(0);\n    instance.visitInsn(Opcodes.AALOAD);\n    assertEquals(expected2, instance.introspect().stack.peek());\n  }\n\n  private static Object[] conversionTypes(int conversionOp) {\n    switch (conversionOp) {\n      case Opcodes.I2B:\n      case Opcodes.I2S:\n      case Opcodes.I2C:\n        return new Object[] {1, 1, Opcodes.INTEGER};\n      case Opcodes.I2D:\n        return new Object[] {\n          1, 2, new Object[] {InstrumentingMethodVisitor.TOP_EXT, Opcodes.DOUBLE}\n        };\n      case Opcodes.I2F:\n        return new Object[] {1, 1, Opcodes.FLOAT};\n      case Opcodes.I2L:\n        return new Object[] {1, 2, new Object[] {InstrumentingMethodVisitor.TOP_EXT, Opcodes.LONG}};\n      case Opcodes.F2I:\n        return new Object[] {1f, 1, Opcodes.INTEGER};\n      case Opcodes.F2D:\n        return new Object[] {\n          1f, 2, new Object[] {InstrumentingMethodVisitor.TOP_EXT, Opcodes.DOUBLE}\n        };\n      case Opcodes.F2L:\n        return new Object[] {\n          1f, 2, new Object[] {InstrumentingMethodVisitor.TOP_EXT, Opcodes.LONG}\n        };\n      case Opcodes.L2I:\n        return new Object[] {1L, 1, Opcodes.INTEGER};\n      case Opcodes.L2F:\n        return new Object[] {1L, 1, Opcodes.FLOAT};\n      case Opcodes.L2D:\n        return new Object[] {\n          1L, 2, new Object[] {InstrumentingMethodVisitor.TOP_EXT, Opcodes.DOUBLE}\n        };\n      case Opcodes.D2I:\n        return new Object[] {1d, 1, Opcodes.INTEGER};\n      case Opcodes.D2F:\n        return new Object[] {1d, 1, Opcodes.FLOAT};\n      case Opcodes.D2L:\n        return new Object[] {\n          1d, 2, new Object[] {InstrumentingMethodVisitor.TOP_EXT, Opcodes.LONG}\n        };\n    }\n    return null;\n  }\n\n  @ParameterizedTest\n  @ValueSource(ints = {Opcodes.F_FULL, Opcodes.F_NEW})\n  void visitFrameNew(int opcode) {\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 1);\n\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitVarInsn(Opcodes.ALOAD, 1);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(2, i.lvTypes.size());\n\n    Object[] newStack = new Object[] {Opcodes.FLOAT};\n    Object[] newLocals = new Object[] {Opcodes.FLOAT};\n\n    instance.visitFrame(opcode, newLocals.length, newLocals, newStack.length, newStack);\n\n    i = instance.introspect();\n\n    assertArrayEquals(newStack, i.stack.toArray());\n    assertArrayEquals(newLocals, i.lvTypes.toArray());\n  }\n\n  @ParameterizedTest\n  @ValueSource(ints = {Opcodes.F_FULL, Opcodes.F_NEW})\n  void visitFrameNewWithNewVar(int opcode) {\n    instance.visitLdcInsn(-1);\n    int newIdx = instance.storeAsNew();\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 1);\n\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitVarInsn(Opcodes.ALOAD, 1);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(3, i.lvTypes.size());\n\n    Object[] newStack = new Object[] {Opcodes.FLOAT};\n    Object[] newLocals = new Object[] {Opcodes.FLOAT};\n\n    instance.visitFrame(opcode, newLocals.length, newLocals, newStack.length, newStack);\n\n    i = instance.introspect();\n\n    assertArrayEquals(newStack, i.stack.toArray());\n    assertEquals(Opcodes.INTEGER, i.lvTypes.getType(0));\n    Object[] toCheck = new Object[i.lvTypes.size() - 1];\n    System.arraycopy(i.lvTypes.toArray(), 1, toCheck, 0, toCheck.length);\n    assertArrayEquals(newLocals, toCheck);\n  }\n\n  @Test\n  void visitFrameSame() {\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 1);\n\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitVarInsn(Opcodes.ALOAD, 1);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(2, i.lvTypes.size());\n\n    Object[] oldLocals = i.lvTypes.toArray();\n    Object[] newStack = new Object[] {Opcodes.FLOAT};\n    Object[] newLocals = new Object[] {Opcodes.FLOAT};\n\n    instance.visitFrame(Opcodes.F_NEW, i.lvTypes.size(), i.lvTypes.toArray(), 0, null);\n    instance.visitIincInsn(0, 1);\n    instance.visitFrame(Opcodes.F_SAME, newLocals.length, newLocals, newStack.length, newStack);\n\n    i = instance.introspect();\n\n    assertArrayEquals(new Object[0], i.stack.toArray());\n    assertArrayEquals(oldLocals, i.lvTypes.toArray());\n  }\n\n  @Test\n  void visitFrameSameWithNewVar() {\n    instance.visitLdcInsn(-1);\n    int newIdx = instance.storeAsNew();\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 1);\n\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitVarInsn(Opcodes.ALOAD, 1);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(3, i.lvTypes.size());\n\n    Object[] origLocals = new Object[] {Opcodes.INTEGER, \"java/lang/String\"};\n    Object[] newStack = new Object[] {Opcodes.FLOAT};\n    Object[] newLocals = new Object[] {Opcodes.FLOAT};\n\n    instance.visitFrame(Opcodes.F_NEW, origLocals.length, origLocals, 0, null);\n    Object[] frameLocals = instance.introspect().lvTypes.toArray();\n\n    instance.visitIincInsn(0, 1);\n    instance.visitFrame(Opcodes.F_SAME, newLocals.length, newLocals, newStack.length, newStack);\n\n    i = instance.introspect();\n\n    assertArrayEquals(new Object[0], i.stack.toArray());\n    assertArrayEquals(frameLocals, i.lvTypes.toArray());\n  }\n\n  @Test\n  void visitFrameSame1() {\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 1);\n\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitVarInsn(Opcodes.ALOAD, 1);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(2, i.lvTypes.size());\n\n    Object[] oldLocals = i.lvTypes.toArray();\n    Object[] newStack = new Object[] {Opcodes.FLOAT};\n    Object[] newLocals = new Object[] {Opcodes.FLOAT};\n\n    instance.visitFrame(Opcodes.F_NEW, i.lvTypes.size(), i.lvTypes.toArray(), 0, null);\n    instance.visitIincInsn(0, 1);\n    instance.visitFrame(Opcodes.F_SAME1, newLocals.length, newLocals, newStack.length, newStack);\n\n    i = instance.introspect();\n\n    assertEquals(1, i.stack.size());\n    assertEquals(Opcodes.FLOAT, i.stack.peek());\n    assertArrayEquals(oldLocals, i.lvTypes.toArray());\n  }\n\n  @Test\n  void visitFrameSame1WithNewVar() {\n    instance.visitLdcInsn(-1);\n    int newIdx = instance.storeAsNew();\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 1);\n\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitVarInsn(Opcodes.ALOAD, 1);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(3, i.lvTypes.size());\n\n    Object[] origLocals = new Object[] {Opcodes.INTEGER, \"java/lang/String\"};\n    Object[] newStack = new Object[] {Opcodes.FLOAT};\n    Object[] newLocals = new Object[] {Opcodes.FLOAT};\n\n    instance.visitFrame(Opcodes.F_NEW, origLocals.length, origLocals, 0, null);\n    Object[] frameLocals = instance.introspect().lvTypes.toArray();\n\n    instance.visitIincInsn(0, 1);\n    instance.visitFrame(Opcodes.F_SAME1, newLocals.length, newLocals, newStack.length, newStack);\n\n    i = instance.introspect();\n\n    assertEquals(1, i.stack.size());\n    assertEquals(Opcodes.FLOAT, i.stack.peek());\n    assertArrayEquals(frameLocals, i.lvTypes.toArray());\n  }\n\n  @Test\n  void visitFrameAppend() {\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 1);\n\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitVarInsn(Opcodes.ALOAD, 1);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(2, i.lvTypes.size());\n\n    Object[] oldLocals = i.lvTypes.toArray();\n    Object[] newStack = new Object[] {Opcodes.FLOAT};\n    Object[] newLocals = new Object[] {Opcodes.FLOAT};\n\n    instance.visitFrame(Opcodes.F_NEW, i.lvTypes.size(), i.lvTypes.toArray(), 0, null);\n    instance.visitIincInsn(0, 1);\n    instance.visitLdcInsn(1f);\n    instance.visitVarInsn(Opcodes.FSTORE, 2);\n    instance.visitFrame(Opcodes.F_APPEND, newLocals.length, newLocals, newStack.length, newStack);\n\n    i = instance.introspect();\n\n    assertEquals(0, i.stack.size());\n    assertEquals(oldLocals.length + newLocals.length, i.lvTypes.size());\n    assertEquals(Opcodes.FLOAT, i.lvTypes.getType(2));\n  }\n\n  @Test\n  void visitFrameAppendWithNewVar() {\n    instance.visitLdcInsn(-1);\n    int newIdx = instance.storeAsNew();\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 1);\n\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitVarInsn(Opcodes.ALOAD, 1);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(3, i.lvTypes.size());\n\n    Object[] origLocals = new Object[] {Opcodes.INTEGER, \"java/lang/String\"};\n    Object[] newStack = new Object[] {Opcodes.FLOAT};\n    Object[] newLocals = new Object[] {Opcodes.FLOAT};\n\n    instance.visitFrame(Opcodes.F_NEW, origLocals.length, origLocals, 0, null);\n    Object[] frameLocals = instance.introspect().lvTypes.toArray();\n\n    instance.visitIincInsn(0, 1);\n    instance.visitLdcInsn(1f);\n    instance.visitVarInsn(Opcodes.FSTORE, 2);\n    instance.visitFrame(Opcodes.F_APPEND, newLocals.length, newLocals, newStack.length, newStack);\n\n    i = instance.introspect();\n\n    assertEquals(0, i.stack.size());\n    assertEquals(frameLocals.length + newLocals.length, i.lvTypes.size());\n    assertEquals(Opcodes.FLOAT, i.lvTypes.getType(3));\n  }\n\n  @Test\n  void visitFrameChop() {\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 1);\n\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitVarInsn(Opcodes.ALOAD, 1);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(2, i.lvTypes.size());\n\n    Object[] newStack = new Object[] {Opcodes.FLOAT};\n    Object[] newLocals = new Object[] {Opcodes.FLOAT};\n\n    instance.visitFrame(Opcodes.F_NEW, i.lvTypes.size(), i.lvTypes.toArray(), 0, null);\n    instance.visitIincInsn(0, 1);\n    instance.visitFrame(Opcodes.F_CHOP, 1, newLocals, newStack.length, newStack);\n\n    i = instance.introspect();\n\n    assertEquals(0, i.stack.size());\n    assertEquals(1, i.lvTypes.size());\n  }\n\n  @Test\n  void visitFrameChopWithNewVar() {\n    instance.visitLdcInsn(-1);\n    int newIdx = instance.storeAsNew();\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 1);\n\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitVarInsn(Opcodes.ALOAD, 1);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(2, i.stack.size());\n    assertEquals(3, i.lvTypes.size());\n\n    Object[] origLocals = new Object[] {Opcodes.INTEGER, \"java/lang/String\"};\n    Object[] newStack = new Object[] {Opcodes.FLOAT};\n    Object[] newLocals = new Object[] {Opcodes.FLOAT};\n\n    instance.visitFrame(Opcodes.F_NEW, origLocals.length, origLocals, 0, null);\n\n    instance.visitIincInsn(0, 1);\n    instance.visitFrame(Opcodes.F_CHOP, 1, newLocals, newStack.length, newStack);\n\n    i = instance.introspect();\n\n    assertEquals(0, i.stack.size());\n    assertEquals(2, i.lvTypes.size());\n  }\n\n  @Test\n  void visitLookupSwitch() {\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitInsn(Opcodes.DUP);\n\n    Label target = new Label();\n    instance.visitLookupSwitchInsn(target, new int[] {1}, new Label[] {target});\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.jumpTable.size());\n    assertEquals(target, i.jumpTable.keySet().iterator().next());\n    instance.visitLdcInsn(1f);\n    instance.visitVarInsn(Opcodes.FSTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n\n    instance.visitLabel(target);\n    InstrumentingMethodVisitor.Introspection i1 = instance.introspect();\n\n    assertArrayEquals(i.stack.toArray(), i1.stack.toArray());\n    assertArrayEquals(i.lvTypes.toArray(), i1.lvTypes.toArray());\n  }\n\n  @Test\n  void visitLookupTable() {\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitInsn(Opcodes.DUP);\n\n    Label target = new Label();\n    instance.visitTableSwitchInsn(1, 1, target, target);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.jumpTable.size());\n    assertEquals(target, i.jumpTable.keySet().iterator().next());\n    instance.visitLdcInsn(1f);\n    instance.visitVarInsn(Opcodes.FSTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n\n    instance.visitLabel(target);\n    InstrumentingMethodVisitor.Introspection i1 = instance.introspect();\n\n    assertArrayEquals(i.stack.toArray(), i1.stack.toArray());\n    assertArrayEquals(i.lvTypes.toArray(), i1.lvTypes.toArray());\n  }\n\n  @ParameterizedTest\n  @ValueSource(ints = {Opcodes.GOTO, Opcodes.JSR})\n  void visitJump(int opcode) {\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n\n    Label target = new Label();\n    instance.visitJumpInsn(opcode, target);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.jumpTable.size());\n    assertEquals(target, i.jumpTable.keySet().iterator().next());\n    instance.visitLdcInsn(1f);\n    instance.visitVarInsn(Opcodes.FSTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n\n    instance.visitLabel(target);\n    InstrumentingMethodVisitor.Introspection i1 = instance.introspect();\n\n    assertArrayEquals(i.stack.toArray(), i1.stack.toArray());\n    assertArrayEquals(i.lvTypes.toArray(), i1.lvTypes.toArray());\n  }\n\n  @ParameterizedTest\n  @ValueSource(\n      ints = {\n        Opcodes.IFEQ,\n        Opcodes.IFGT,\n        Opcodes.IFGE,\n        Opcodes.IFLT,\n        Opcodes.IFLE,\n        Opcodes.IFNE,\n        Opcodes.IFNONNULL,\n        Opcodes.IFNULL\n      })\n  void visitJumpInsnUnary(int opcode) {\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitInsn(Opcodes.DUP);\n\n    Label target = new Label();\n    instance.visitJumpInsn(opcode, target);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.jumpTable.size());\n    assertEquals(target, i.jumpTable.keySet().iterator().next());\n    instance.visitLdcInsn(1f);\n    instance.visitVarInsn(Opcodes.FSTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n\n    instance.visitLabel(target);\n    InstrumentingMethodVisitor.Introspection i1 = instance.introspect();\n\n    assertArrayEquals(i.stack.toArray(), i1.stack.toArray());\n    assertArrayEquals(i.lvTypes.toArray(), i1.lvTypes.toArray());\n  }\n\n  @ParameterizedTest\n  @ValueSource(\n      ints = {\n        Opcodes.IF_ACMPEQ, Opcodes.IF_ACMPNE, Opcodes.IF_ICMPEQ, Opcodes.IF_ICMPGE,\n        Opcodes.IF_ICMPGT, Opcodes.IF_ICMPLE, Opcodes.IF_ICMPLT, Opcodes.IF_ICMPNE\n      })\n  void visitJumpInsnBinary(int opcode) {\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n    instance.visitInsn(Opcodes.DUP2);\n\n    Label target = new Label();\n    instance.visitJumpInsn(opcode, target);\n\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.jumpTable.size());\n    assertEquals(target, i.jumpTable.keySet().iterator().next());\n    instance.visitLdcInsn(1f);\n    instance.visitVarInsn(Opcodes.FSTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n\n    instance.visitLabel(target);\n    InstrumentingMethodVisitor.Introspection i1 = instance.introspect();\n\n    assertArrayEquals(i.stack.toArray(), i1.stack.toArray());\n    assertArrayEquals(i.lvTypes.toArray(), i1.lvTypes.toArray());\n  }\n\n  @Test\n  void visitTryCatch() {\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 0);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 1);\n    instance.visitVarInsn(Opcodes.ALOAD, 1);\n    instance.visitVarInsn(Opcodes.ILOAD, 0);\n\n    Label start = new Label();\n    Label end = new Label();\n    Label over = new Label();\n    instance.visitTryCatchBlock(start, end, end, \"java/lang/InterruptedException\");\n    instance.visitLabel(start);\n    instance.visitLdcInsn(1f);\n    instance.visitInsn(Opcodes.DUP);\n    instance.visitVarInsn(Opcodes.FSTORE, 2);\n    InstrumentingMethodVisitor.Introspection i1 = instance.introspect();\n    assertEquals(Opcodes.FLOAT, i1.stack.peek());\n    assertEquals(3, i1.lvTypes.size());\n    assertEquals(Opcodes.FLOAT, i1.lvTypes.getType(2));\n\n    instance.visitJumpInsn(Opcodes.GOTO, over);\n    instance.visitLabel(end);\n    InstrumentingMethodVisitor.Introspection i2 = instance.introspect();\n    assertEquals(3, i2.stack.size());\n    assertEquals(\"java/lang/Throwable\", i2.stack.peek());\n\n    instance.visitInsn(Opcodes.POP);\n    instance.visitLabel(over);\n    InstrumentingMethodVisitor.Introspection i3 = instance.introspect();\n    assertEquals(3, i3.stack.size());\n    assertEquals(Opcodes.FLOAT, i3.stack.peek());\n  }\n\n  @Test\n  void visitMethodInsnVoid() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n\n    String desc = \"(ILjava/langString;)V\";\n    instance.visitMethodInsn(Opcodes.INVOKESTATIC, \"test/Main\", \"main\", desc, false);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(0, i.stack.size());\n\n    instance.visitVarInsn(Opcodes.ALOAD, 0);\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitMethodInsn(Opcodes.INVOKEVIRTUAL, \"test/Main\", \"main\", desc, false);\n    assertEquals(0, i.stack.size());\n\n    instance.visitVarInsn(Opcodes.ALOAD, 0);\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitMethodInsn(Opcodes.INVOKEINTERFACE, \"test/Main\", \"main\", desc, true);\n    assertEquals(0, i.stack.size());\n\n    instance.visitVarInsn(Opcodes.ALOAD, 0);\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitMethodInsn(Opcodes.INVOKESPECIAL, \"test/Main\", \"<init>\", desc, false);\n    assertEquals(0, i.stack.size());\n  }\n\n  @Test\n  void visitMethodInsnRet() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n\n    String desc = \"(ILjava/lang/String;)I\";\n    instance.visitMethodInsn(Opcodes.INVOKESTATIC, \"test/Main\", \"main\", desc, false);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.stack.size());\n\n    instance.visitVarInsn(Opcodes.ALOAD, 0);\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitMethodInsn(Opcodes.INVOKEVIRTUAL, \"test/Main\", \"main\", desc, false);\n    assertEquals(1, i.stack.size());\n\n    instance.visitVarInsn(Opcodes.ALOAD, 0);\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitMethodInsn(Opcodes.INVOKEINTERFACE, \"test/Main\", \"main\", desc, true);\n    assertEquals(1, i.stack.size());\n  }\n\n  @Test\n  void visitDynamicMethodInsnVoid() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n\n    Handle h = new Handle(Opcodes.H_INVOKESTATIC, \"bootstrap.Bill\", \"bootstrap\", \"(IZ)V\", false);\n    String desc = \"(ILjava/langString;)V\";\n    instance.visitInvokeDynamicInsn(\"main\", desc, h, 1, false);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(0, i.stack.size());\n  }\n\n  @Test\n  void visitDynamicMethodInsnRet() {\n    instance.visitLdcInsn(1);\n    instance.visitLdcInsn(\"hello\");\n\n    Handle h = new Handle(Opcodes.H_INVOKESTATIC, \"bootstrap.Bill\", \"bootstrap\", \"(IZ)V\", false);\n    String desc = \"(ILjava/lang/String;)I\";\n    instance.visitInvokeDynamicInsn(\"main\", desc, h, 1, false);\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(1, i.stack.size());\n  }\n\n  @ParameterizedTest\n  @ValueSource(ints = {Opcodes.GETFIELD, Opcodes.GETSTATIC, Opcodes.PUTFIELD, Opcodes.PUTSTATIC})\n  void visitFieldInsn(int opcode) {\n    if (opcode == Opcodes.GETFIELD || opcode == Opcodes.PUTFIELD) {\n      instance.visitVarInsn(Opcodes.ALOAD, 0); // load 'this'\n    }\n    if (opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC) {\n      instance.visitVarInsn(Opcodes.ILOAD, 1); // load value\n    }\n    instance.visitFieldInsn(opcode, \"test/Main\", \"f\", \"I\");\n    InstrumentingMethodVisitor.Introspection i = instance.introspect();\n    assertEquals(opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC ? 0 : 1, i.stack.size());\n  }\n\n  @Test\n  void insertFrameReplaceStack() {\n    Label l = new Label();\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 1);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 2);\n    instance.visitVarInsn(Opcodes.ALOAD, 2);\n    instance.visitVarInsn(Opcodes.ILOAD, 1);\n    instance.visitJumpInsn(Opcodes.GOTO, l); // label needs to have jump target\n    instance.visitLabel(l);\n\n    instance.insertFrameReplaceStack(l, Type.getType(String.class), Type.FLOAT_TYPE);\n    LastVisitedFrame expected =\n        new LastVisitedFrame(\n            Opcodes.F_NEW,\n            2,\n            new Object[] {Opcodes.INTEGER, \"java/lang/String\"},\n            2,\n            new Object[] {\"java/lang/String\", Opcodes.FLOAT});\n    assertEquals(expected, lastVisitedFrame);\n  }\n\n  @Test\n  void insertFrameAppendStack() {\n    Label l = new Label();\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 1);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 2);\n    instance.visitVarInsn(Opcodes.ALOAD, 2);\n    instance.visitVarInsn(Opcodes.ILOAD, 1);\n    instance.visitJumpInsn(Opcodes.GOTO, l); // label needs to have jump target\n    instance.visitLabel(l);\n\n    instance.insertFrameAppendStack(l, Type.FLOAT_TYPE);\n    LastVisitedFrame expected =\n        new LastVisitedFrame(\n            Opcodes.F_NEW,\n            2,\n            new Object[] {Opcodes.INTEGER, \"java/lang/String\"},\n            3,\n            new Object[] {\"java/lang/String\", Opcodes.INTEGER, Opcodes.FLOAT});\n    assertEquals(expected, lastVisitedFrame);\n  }\n\n  @Test\n  void insertFrameAppendStackWithLongOnStack() {\n    Label l = new Label();\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 1);\n    instance.visitLdcInsn(100L); // Push long (2 slots)\n    instance.visitJumpInsn(Opcodes.GOTO, l);\n    instance.visitLabel(l);\n\n    instance.insertFrameAppendStack(l, Type.INT_TYPE); // Append int to stack with long\n\n    // Verify frame uses compact ASM API format: [LONG, INTEGER] without TOP marker.\n    // ASM's visitFrame() expects category-2 types (long/double) as single elements.\n    // ASM internally expands this to JVMS bytecode format [long, top, int].\n    LastVisitedFrame expected =\n        new LastVisitedFrame(\n            Opcodes.F_NEW,\n            1,\n            new Object[] {Opcodes.INTEGER},\n            2,\n            new Object[] {Opcodes.LONG, Opcodes.INTEGER});\n    assertEquals(expected, lastVisitedFrame);\n  }\n\n  @Test\n  void insertFrameAppendStackWithDoubleOnStack() {\n    Label l = new Label();\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 1);\n    instance.visitLdcInsn(3.14); // Push double (2 slots)\n    instance.visitJumpInsn(Opcodes.GOTO, l);\n    instance.visitLabel(l);\n\n    instance.insertFrameAppendStack(l, Type.getType(String.class)); // Append String\n\n    // Verify frame uses compact ASM API format: [DOUBLE, String] without TOP marker.\n    // ASM's visitFrame() expects category-2 types (long/double) as single elements.\n    // ASM internally expands this to JVMS bytecode format [double, top, String].\n    LastVisitedFrame expected =\n        new LastVisitedFrame(\n            Opcodes.F_NEW,\n            1,\n            new Object[] {Opcodes.INTEGER},\n            2,\n            new Object[] {Opcodes.DOUBLE, \"java/lang/String\"});\n    assertEquals(expected, lastVisitedFrame);\n  }\n\n  @Test\n  void insertFrameSameStack() {\n    Label l = new Label();\n    instance.visitLdcInsn(1);\n    instance.visitVarInsn(Opcodes.ISTORE, 1);\n    instance.visitLdcInsn(\"hello\");\n    instance.visitVarInsn(Opcodes.ASTORE, 2);\n    instance.visitVarInsn(Opcodes.ALOAD, 2);\n    instance.visitVarInsn(Opcodes.ILOAD, 1);\n    instance.visitJumpInsn(Opcodes.GOTO, l); // label needs to have jump target\n    instance.visitLabel(l);\n\n    instance.insertFrameSameStack(l);\n    LastVisitedFrame expected =\n        new LastVisitedFrame(\n            Opcodes.F_NEW,\n            2,\n            new Object[] {Opcodes.INTEGER, \"java/lang/String\"},\n            2,\n            new Object[] {\"java/lang/String\", Opcodes.INTEGER});\n    assertEquals(expected, lastVisitedFrame);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/InstrumentorTestBase.java",
    "content": "/*\n * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.instr;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.ClassWriter;\nimport org.objectweb.asm.Opcodes;\nimport org.objectweb.asm.tree.ClassNode;\nimport org.objectweb.asm.util.CheckClassAdapter;\nimport org.objectweb.asm.util.TraceClassVisitor;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.MethodID;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.runtime.BTraceRuntimeAccess;\nimport org.openjdk.btrace.runtime.auxiliary.Auxiliary;\nimport sun.misc.Unsafe;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.lang.reflect.Field;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.fail;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic abstract class InstrumentorTestBase {\n  private static final boolean DEBUG = false;\n  private static final SharedSettings settings = SharedSettings.GLOBAL;\n  private static final BTraceProbeFactory factory = new BTraceProbeFactory(settings);\n  private static Unsafe unsafe;\n  private static Field uccn = null;\n\n  protected byte[] originalBC;\n  protected byte[] transformedBC;\n  protected byte[] traceCode;\n  private static ClassLoader cl;\n\n  static {\n    try {\n      Field unsafeFld = AtomicInteger.class.getDeclaredField(\"unsafe\");\n      unsafeFld.setAccessible(true);\n      unsafe = (Unsafe) unsafeFld.get(null);\n      resetClassLoader();\n    } catch (Exception e) {\n    }\n  }\n\n  @BeforeAll\n  public static void classStartup() throws Exception {\n    BTraceRuntime.class.getName();\n    uccn = BTraceRuntimeAccess.class.getDeclaredField(\"uniqueClientClassNames\");\n    uccn.setAccessible(true);\n    uccn.set(null, true);\n    settings.setTrusted(true);\n  }\n\n  protected final void enableUniqueClientClassNameCheck() throws Exception {\n    uccn.set(null, true);\n  }\n\n  protected final void disableUniqueClientClassNameCheck() throws Exception {\n    uccn.set(null, false);\n  }\n\n  @AfterEach\n  public void tearDown() {\n    cleanup();\n  }\n\n  @BeforeEach\n  public void startup() {\n    try {\n      originalBC = null;\n      transformedBC = null;\n      traceCode = null;\n      resetClassLoader();\n\n      Field lastFld = MethodID.class.getDeclaredField(\"lastMethodId\");\n      Field mapFld = MethodID.class.getDeclaredField(\"methodIds\");\n\n      lastFld.setAccessible(true);\n      mapFld.setAccessible(true);\n\n      AtomicInteger last = (AtomicInteger) lastFld.get(null);\n      Map<String, Integer> map = (Map<String, Integer>) mapFld.get(null);\n\n      last.set(1);\n      map.clear();\n      disableUniqueClientClassNameCheck();\n    } catch (Exception ex) {\n      throw new RuntimeException(ex);\n    }\n  }\n\n  protected static final void resetClassLoader() {\n    cl = new ClassLoader(InstrumentorTestBase.class.getClassLoader()) {\n    };\n  }\n\n  protected void cleanup() {\n    originalBC = null;\n    transformedBC = null;\n    traceCode = null;\n  }\n\n  protected void load(final String traceName, final String clzName) throws Exception {\n    loadTraceCode(traceName);\n    loadClass(clzName);\n  }\n\n  @SuppressWarnings(\"ClassNewInstance\")\n  protected void loadClass(String origName) throws Exception {\n    if (transformedBC != null) {\n      String clzName = new ClassReader(transformedBC).getClassName().replace('.', '/');\n      Class<?> clz = unsafe.defineClass(clzName, transformedBC, 0, transformedBC.length, cl, null);\n      try {\n        clz.newInstance();\n      } catch (NoSuchFieldError | NoClassDefFoundError e) {\n        // expected; ignore\n      }\n    } else {\n      System.err.println(\"Unable to instrument class \" + origName);\n      transformedBC = originalBC;\n    }\n  }\n\n  @SuppressWarnings(\"ClassNewInstance\")\n  protected void loadTraceCode(String origName) throws Exception {\n    if (traceCode != null) {\n      String traceName = new ClassReader(traceCode).getClassName().replace('.', '/');\n      Class<?> clz = unsafe.defineClass(traceName, traceCode, 0, traceCode.length, cl, null);\n      clz.newInstance();\n    } else {\n      System.err.println(\"Unable to process trace \" + origName);\n    }\n  }\n\n  @SuppressWarnings(\"ClassNewInstance\")\n  public static void loadCode(String origName, byte[] code) throws Exception {\n    if (code != null) {\n      ClassReader cr = new ClassReader(code);\n      String traceName = cr.getClassName().replace('.', '/');\n      Class<?> clz = null;\n      try {\n        clz = unsafe.defineClass(traceName, code, 0, code.length, cl, null);\n        clz.newInstance();\n      } catch (NoSuchMethodError e) {\n        ClassWriter cw = new ClassWriter(0);\n        ClassVisitor cv =\n                new ClassVisitor(Opcodes.ASM9, cw) {\n                  @Override\n                  public void visit(\n                          int version,\n                          int access,\n                          String name,\n                          String signature,\n                          String superName,\n                          String[] interfaces) {\n                    int idx = name.lastIndexOf('/');\n                    name =\n                            Auxiliary.class.getPackage().getName().replace('.', '/')\n                                    + '/'\n                                    + name.substring(idx + 1);\n                    super.visit(version, access, name, signature, superName, interfaces);\n                  }\n                };\n        cr.accept(cv, ClassReader.SKIP_DEBUG);\n        code = cw.toByteArray();\n        Class<?> rtClz = Class.forName(\"org.openjdk.btrace.runtime.BTraceRuntimeImpl_9\");\n        rtClz.getMethod(\"defineClassInAuxiliary\", byte[].class).invoke(null, code);\n      }\n    } else {\n      System.err.println(\"Unable to process trace \" + origName);\n    }\n  }\n\n  protected void checkTransformation(String name) throws IOException {\n    checkTransformation(name, true);\n  }\n\n  protected void checkTransformation(String name, boolean verify) throws IOException {\n    org.objectweb.asm.ClassReader cr = new org.objectweb.asm.ClassReader(transformedBC);\n\n    if (verify) {\n      StringWriter sw = new StringWriter();\n      PrintWriter pw = new PrintWriter(sw);\n      CheckClassAdapter.verify(cr, true, pw);\n      if (sw.toString().contains(\"AnalyzerException\")) {\n        System.err.println(sw);\n        fail();\n      }\n    }\n\n    String diff = diff();\n    if (DEBUG) {\n      System.err.println(diff);\n    }\n//    if (name.isEmpty()) {\n//      assertTrue(diff.isEmpty());\n//    }\n    Path target = Paths.get(System.getProperty(\"test.resources\"), \"instrumentorTestData\", name);\n    if (Boolean.getBoolean(\"update.test.data\")) {\n      Files.createDirectories(target.getParent());\n      Files.write(target, diff.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);\n    } else {\n      String expected = new String(Files.readAllBytes(target), StandardCharsets.UTF_8);\n      assertEquals(expected, diff);\n    }\n  }\n\n  protected void checkTrace(String expected) throws IOException {\n    org.objectweb.asm.ClassReader cr = new org.objectweb.asm.ClassReader(traceCode);\n\n    StringWriter sw = new StringWriter();\n    PrintWriter pw = new PrintWriter(sw);\n    CheckClassAdapter.verify(cr, false, pw);\n    if (sw.toString().contains(\"AnalyzerException\")) {\n      System.err.println(sw);\n      fail();\n    }\n  }\n\n  protected void transform(String traceName) throws Exception {\n    transform(traceName, false);\n  }\n\n  protected void transform(String traceName, boolean unsafe) throws Exception {\n    settings.setTrusted(unsafe);\n    BTraceClassReader cr = InstrumentUtils.newClassReader(cl, originalBC);\n    BTraceClassWriter cw = InstrumentUtils.newClassWriter(cr);\n    BTraceProbe btrace = loadTrace(traceName, unsafe);\n\n    cw.addInstrumentor(btrace);\n\n    transformedBC = cw.instrument();\n\n    if (transformedBC != null) {\n      try (OutputStream os = new FileOutputStream(new File(System.getProperty(\"java.io.tmpdir\"), \"dummy.class\"))) {\n        os.write(transformedBC);\n      }\n    } else {\n      // if the instrumentation returns 'null' the original code is to be used\n      transformedBC = originalBC;\n    }\n\n    //        load(traceName, cr.getJavaClassName());\n\n    System.err.println(\"==== \" + traceName);\n  }\n\n  public static String asmify(byte[] bytecode) {\n    StringWriter sw = new StringWriter();\n    TraceClassVisitor acv = new TraceClassVisitor(new PrintWriter(sw));\n    new org.objectweb.asm.ClassReader(bytecode).accept(acv, 0);\n    return sw.toString();\n  }\n\n  public static String asmify(ClassNode cn) {\n    ClassWriter cw = new ClassWriter(0);\n    cn.accept(cw);\n    return asmify(cw.toByteArray());\n  }\n\n  private String diff() throws IOException {\n    String origCode = asmify(originalBC);\n    String transCode = asmify(transformedBC);\n    return diff(transCode, origCode);\n  }\n\n  private String diff(String modified, String orig) throws IOException {\n    StringBuilder sb = new StringBuilder();\n\n    String[] modArr = modified.split(\"\\\\n\");\n    String[] orgArr = orig.split(\"\\\\n\");\n\n    // number of lines of each file\n    int modLen = modArr.length;\n    int origLen = orgArr.length;\n\n    // opt[i][j] = length of LCS of x[i..M] and y[j..N]\n    int[][] opt = new int[modLen + 1][origLen + 1];\n\n    // compute length of LCS and all subproblems via dynamic programming\n    for (int i = modLen - 1; i >= 0; i--) {\n      for (int j = origLen - 1; j >= 0; j--) {\n        if (modArr[i].equals(orgArr[j])) {\n          opt[i][j] = opt[i + 1][j + 1] + 1;\n        } else {\n          opt[i][j] = Math.max(opt[i + 1][j], opt[i][j + 1]);\n        }\n      }\n    }\n\n    // recover LCS itself and print out non-matching lines to standard output\n    int modIndex = 0;\n    int origIndex = 0;\n    while (modIndex < modLen && origIndex < origLen) {\n      if (modArr[modIndex].equals(orgArr[origIndex])) {\n        modIndex++;\n        origIndex++;\n      } else if (opt[modIndex + 1][origIndex] >= opt[modIndex][origIndex + 1]) {\n        sb.append(modArr[modIndex++].trim()).append('\\n');\n      } else {\n        origIndex++;\n      }\n    }\n\n    // dump out one remainder of one string if the other is exhausted\n    while (modIndex < modLen || origIndex < origLen) {\n      if (modIndex == modLen) {\n        origIndex++;\n      } else if (origIndex == origLen) {\n        sb.append(orgArr[modIndex++].trim()).append('\\n');\n      }\n    }\n    return sb.toString().trim();\n  }\n\n  protected BTraceProbe loadTrace(String name) throws IOException {\n    return loadTrace(name, false);\n  }\n\n  protected BTraceProbe loadTrace(String name, boolean unsafe) throws IOException {\n    byte[] traceData = loadFile(\"traces/\" + name + \".class\");\n\n    BTraceProbe bcn = factory.createProbe(traceData);\n    traceCode = bcn.getFullBytecode();\n\n    if (DEBUG) {\n      System.err.println(\"=== Loaded Trace: \" + bcn + \"\\n\");\n      System.err.println(asmify(this.traceCode));\n      Files.write(FileSystems.getDefault().getPath(System.getProperty(\"java.io.tmpdir\"), \"jingle.class\"), traceCode);\n    }\n\n    bcn.checkVerified();\n\n    return bcn;\n  }\n\n  protected byte[] loadTargetClass(String name) throws IOException {\n    originalBC = loadResource(\"/resources/\" + name + \".class\");\n    if (originalBC == null) {\n      originalBC = loadResource(\"/resources/\" + name + \".clazz\");\n    }\n    return originalBC;\n  }\n\n  private byte[] loadResource(final String path) throws IOException {\n    try (final InputStream is = InstrumentorTestBase.class.getResourceAsStream(path)) {\n      if (is == null) {\n        System.err.println(\"Unable to load resource: \" + path);\n        return null;\n      }\n      return loadFile(is);\n    }\n  }\n\n  private byte[] loadFile(String path) throws IOException {\n    File f = new File(\"./build/classes/\" + path);\n    try (InputStream is = new FileInputStream(f)) {\n      byte[] data = loadFile(is);\n      return data;\n    }\n  }\n\n  private byte[] loadFile(InputStream is) throws IOException {\n    // ByteArrayOutputStream uses geometric growth (2× on resize)\n    ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);\n    byte[] buffer = new byte[8192];\n    int read;\n\n    while ((read = is.read(buffer)) != -1) {\n      baos.write(buffer, 0, read);  // Appends to internal buffer\n    }\n\n    return baos.toByteArray();  // Single final copy\n  }\n}"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/MethodCounterTest.java",
    "content": "/*\n * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * @author jbachorik\n */\npublic class MethodCounterTest {\n\n  public MethodCounterTest() {}\n\n  @BeforeAll\n  public static void setUpClass() {}\n\n  @AfterAll\n  public static void tearDownClass() {}\n\n  @BeforeEach\n  public void setUp() {}\n\n  @AfterEach\n  public void tearDown() {}\n\n  /** Test of hit method, of class MethodCounter. */\n  @Test\n  public void testHit() {\n    System.out.println(\"hit\");\n    final int iterations = 3000000;\n    final int mean = 20;\n\n    int methodId = 0;\n\n    MethodTracker.registerCounter(methodId, mean);\n\n    int hits = 0;\n\n    for (int i = 0; i < iterations; i++) {\n      hits += MethodTracker.hit(methodId) ? 1 : 0;\n    }\n    long b = System.nanoTime();\n\n    System.err.println(\"hits = \" + hits);\n\n    assertTrue(Math.abs(mean - (iterations / hits)) < (mean / 10));\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/OnMethodInstrumenterTest.java",
    "content": "/*\n * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport java.lang.reflect.Field;\nimport java.nio.file.FileVisitOption;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Named;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic class OnMethodInstrumenterTest extends InstrumentorTestBase {\n  private static final Map<String, String> targetClassMap = new HashMap<>();\n  private static final Map<String, Boolean> verifyFlagMap = new HashMap<>();\n\n  static {\n    targetClassMap.put(\"onmethod/MatchDerived\", \"DerivedClass\");\n    targetClassMap.put(\"issues/BTRACE22\", \"issues/BTRACE22\");\n    targetClassMap.put(\"issues/BTRACE28\", \"issues/BTRACE28\");\n    targetClassMap.put(\"issues/BTRACE53\", \"DerivedClass\");\n    targetClassMap.put(\"issues/BTRACE87\", \"issues/BTRACE87\");\n    targetClassMap.put(\"issues/BTRACE106\", \"issues/BTRACE106\");\n    targetClassMap.put(\"issues/BTRACE189\", \"Main\");\n    targetClassMap.put(\"issues/BTRACE256\", \"issues/BTRACE256\");\n    targetClassMap.put(\"issues/TezSplitter\", \"classdata/TezSplitter\");\n    targetClassMap.put(\"issues/InterestingVarsTest\", \"InterestingVarsClass\");\n\n    verifyFlagMap.put(\"issues/TezSplitter\", Boolean.FALSE);\n    verifyFlagMap.put(\"ServicesTest\", Boolean.FALSE);\n  }\n\n  private static String getTargetClass(String name) {\n    return targetClassMap.getOrDefault(name, \"OnMethodTest\");\n  }\n\n  private static Boolean getVerifyFlag(String name) {\n    return verifyFlagMap.getOrDefault(name, Boolean.TRUE);\n  }\n\n  @BeforeAll\n  public static void classSetup() throws Exception {\n    Field f = RandomIntProvider.class.getDeclaredField(\"useBtraceEnter\");\n    f.setAccessible(true);\n    f.setBoolean(null, false);\n  }\n\n  @ParameterizedTest\n  @MethodSource(\"listTransformations\")\n  void testTransformation(String trace, String targetClass, boolean verify) throws Exception {\n    loadTargetClass(targetClass);\n    transform(trace);\n\n    checkTransformation(\"dynamic/\" + trace, verify);\n  }\n\n  @SuppressWarnings(\"resource\")\n  private static Stream<Arguments> listTransformations() throws Exception {\n    Path root = Paths.get(\"./build/classes/traces\");\n    return Files.walk(root, FileVisitOption.FOLLOW_LINKS)\n              .filter(Files::isRegularFile)\n              .map(root::relativize)\n              .map(Path::toString)\n              .map(p -> p.replace(\".class\", \"\"))\n              .map(p ->\n                Arguments.of(Named.of(\"Trace: \" + p, p), Named.of(\"Target Class: \" + getTargetClass(p), getTargetClass(p)), Named.of(\"Verify: \" + getVerifyFlag(p), getVerifyFlag(p)))\n              );\n  }\n\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/OnMethodTest.java",
    "content": "/*\n * Copyright (c) 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\npackage org.openjdk.btrace.instr;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.ArgsMap;\n\npublic class OnMethodTest {\n  private ArgsMap instance;\n\n  @BeforeEach\n  public void setUp() {\n    instance = new ArgsMap(new String[] {\"className=ClassA\", \"methodName=methodA\"});\n  }\n\n  @Test\n  public void testApplyArgsValid() {\n    assertEquals(\"/.*\\\\.ClassA/\", instance.template(\"/.*\\\\.${className}/\"));\n    assertEquals(\"methodA\", instance.template(\"${methodName}\"));\n    assertEquals(\"${undefined}\", instance.template(\"${undefined}\"));\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/ProbeClassUnloadingTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.\n */\npackage org.openjdk.btrace.instr;\n\nimport java.io.IOException;\nimport java.lang.ref.WeakReference;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.objectweb.asm.ClassWriter;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.openjdk.btrace.runtime.BTraceRuntimes;\n\n/**\n * Verifies that a probe {@code Class<?>} defined through\n * {@link BTraceRuntime.Impl#defineClass(byte[])} becomes weakly reachable once\n * all caller-held strong references are dropped.\n *\n * <p>This test asserts <strong>weak reachability</strong> only — it does NOT assert that\n * Metaspace has actually unloaded the class, as JVM-level unloading under\n * {@link System#gc()} is not deterministic and is flaky on CI. Weak reachability is the\n * reliable precondition for unloading and is what this test guards.\n *\n * <p>The test exercises whichever {@code BTraceRuntimeImpl_*} the host JDK selects:\n * <ul>\n *   <li>JDK 8  → {@code Unsafe.defineClass} into a fresh {@code new ClassLoader(null){}}.</li>\n *   <li>JDK 9-10 → {@code privateLookupIn(anchor, ...).defineClass} where {@code anchor}\n *       is a per-probe class in a fresh unnamed loader.</li>\n *   <li>JDK 11-14 → same anchor-based path as 9-10.</li>\n *   <li>JDK 15+ path uses {@code defineHiddenClass(code, true)} with no\n *       {@code ClassOption}, so the hidden class is unloadable when its\n *       {@code Class<?>} mirror becomes unreachable.</li>\n * </ul>\n *\n * <p>On JDK 15+ the probe's reported {@code ClassLoader} is the loader of\n * {@code Auxiliary} — shared with the agent — so the loader assertion is conditional:\n * we only require the loader to be collected when it is non-null, distinct from the\n * test's own loader, and distinct from the loader that already owns the BTrace runtime\n * classes themselves.\n */\npublic class ProbeClassUnloadingTest {\n\n  private static final CommandListener NOOP_LISTENER =\n      new CommandListener() {\n        @Override\n        public void onCommand(Command cmd) throws IOException {}\n      };\n\n  @Test\n  public void sameProbeNameCanBeDefinedTwice() throws Exception {\n    // With bootstrap-CL residency this threw LinkageError on the second defineClass.\n    // With per-probe ClassLoader / hidden class, each attach gets its own class\n    // mirror, so the same internal name is legal.\n    String probeName =\n        \"org.openjdk.btrace.runtime.auxiliary.SameNameProbe$\" + System.nanoTime();\n    byte[] bytes = generateMinimalClass(probeName);\n    Class<?> first = defineProbe(probeName, bytes);\n    Class<?> second = defineProbe(probeName, bytes);\n    Assertions.assertNotNull(first);\n    Assertions.assertNotNull(second);\n    Assertions.assertNotSame(\n        first,\n        second,\n        \"Re-define of same-named probe must yield a distinct Class mirror\");\n    // Clean up both runtimes (removeRuntime is idempotent; second call is a no-op).\n    BTraceRuntimes.removeRuntime(probeName);\n  }\n\n  private static Class<?> defineProbe(String probeName, byte[] bytes) {\n    BTraceRuntime.Impl rt =\n        BTraceRuntimes.getRuntime(probeName, new ArgsMap(), NOOP_LISTENER, null);\n    Assertions.assertNotNull(rt, \"runtime must be created\");\n    Class<?> probeClass = rt.defineClass(bytes);\n    Assertions.assertNotNull(probeClass, \"defineClass must succeed\");\n    // Release the runtime GC root so a subsequent getRuntime() for the same name\n    // can install a fresh Impl (and thus a fresh ClassLoader / hidden-class group).\n    BTraceRuntimes.removeRuntime(probeName);\n    return probeClass;\n  }\n\n  @Test\n  public void probeClassWeaklyReachableAfterDefine() throws Exception {\n    WeakReference<?>[] refs = defineAndDropProbe();\n    WeakReference<?> weakClass = refs[0];\n    WeakReference<?> weakLoader = refs[1];\n\n    for (int i = 0; i < 30; i++) {\n      System.gc();\n      System.runFinalization();\n      Thread.sleep(50);\n      if (weakClass.get() == null && (weakLoader == null || weakLoader.get() == null)) {\n        break;\n      }\n    }\n\n    Assertions.assertNull(\n        weakClass.get(),\n        \"probe Class<?> is still strongly reachable after defineClass() caller drops\"\n            + \" its references\");\n    if (weakLoader != null) {\n      Assertions.assertNull(\n          weakLoader.get(),\n          \"per-probe ClassLoader is still strongly reachable after caller drops\"\n              + \" references\");\n    }\n  }\n\n  /**\n   * All strong references to the probe {@code Class<?>}, its {@code ClassLoader}, and\n   * the {@link BTraceRuntime.Impl} live only in this helper method's frame. When it\n   * returns, those locals go out of scope, enabling GC to collect the class.\n   *\n   * <p>Correctness depends on this helper not being inlined into the {@code @Test}\n   * method: inlining would keep the Impl and probe-{@code Class<?>} locals alive in the\n   * test frame across the GC loop, masking any retention regression.\n   */\n  // WARNING: do not inline — test depends on helper-frame locals going out of scope before GC\n  private static WeakReference<?>[] defineAndDropProbe() {\n    // Use the Auxiliary package so the bytes are in the same package as the Lookup\n    // class on the JDK 15+ hidden-class path.\n    String probeName = \"org.openjdk.btrace.runtime.auxiliary.ProbeX$\" + System.nanoTime();\n    BTraceRuntime.Impl rt =\n        BTraceRuntimes.getRuntime(\n            probeName,\n            new ArgsMap(),\n            new CommandListener() {\n              @Override\n              public void onCommand(Command cmd) throws IOException {}\n            },\n            null);\n    Assertions.assertNotNull(rt, \"runtime must be created\");\n\n    byte[] bytes = generateMinimalClass(probeName);\n    Class<?> probeClass = rt.defineClass(bytes);\n    Assertions.assertNotNull(probeClass, \"defineClass must succeed\");\n\n    ClassLoader probeLoader = probeClass.getClassLoader();\n    ClassLoader agentLoader = BTraceRuntime.class.getClassLoader();\n    ClassLoader testLoader = ProbeClassUnloadingTest.class.getClassLoader();\n    boolean loaderIsIsolated =\n        probeLoader != null && probeLoader != agentLoader && probeLoader != testLoader;\n\n    WeakReference<Class<?>> weakClass = new WeakReference<>(probeClass);\n    WeakReference<ClassLoader> weakLoader =\n        loaderIsIsolated ? new WeakReference<>(probeLoader) : null;\n\n    // Release the runtime GC root in BTraceRuntimeAccessImpl.runtimes so the class can be collected.\n    BTraceRuntimes.removeRuntime(probeName);\n\n    return new WeakReference<?>[] {weakClass, weakLoader};\n  }\n\n  /**\n   * Generate a minimal valid {@code .class}: a {@code public} class with a public\n   * no-arg constructor and a public static {@code handler()} that does nothing.\n   */\n  private static byte[] generateMinimalClass(String binaryName) {\n    String internalName = binaryName.replace('.', '/');\n    ClassWriter cw = new ClassWriter(0);\n    cw.visit(\n        Opcodes.V1_8,\n        Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER,\n        internalName,\n        null,\n        \"java/lang/Object\",\n        null);\n\n    MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, \"<init>\", \"()V\", null, null);\n    mv.visitCode();\n    mv.visitVarInsn(Opcodes.ALOAD, 0);\n    mv.visitMethodInsn(\n        Opcodes.INVOKESPECIAL, \"java/lang/Object\", \"<init>\", \"()V\", false);\n    mv.visitInsn(Opcodes.RETURN);\n    mv.visitMaxs(1, 1);\n    mv.visitEnd();\n\n    MethodVisitor h =\n        cw.visitMethod(\n            Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, \"handler\", \"()V\", null, null);\n    h.visitCode();\n    h.visitInsn(Opcodes.RETURN);\n    h.visitMaxs(0, 0);\n    h.visitEnd();\n\n    cw.visitEnd();\n    return cw.toByteArray();\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/ProbeLoaderNewTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport java.io.InputStream;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.SharedSettings;\n\npublic class ProbeLoaderNewTest {\n  private static BTraceProbeFactory BPF;\n  private InputStream classStream;\n  private byte[] defData;\n\n  @BeforeAll\n  public static void setupClass() throws Exception {\n    BPF = new BTraceProbeFactory(SharedSettings.GLOBAL);\n  }\n\n  @BeforeEach\n  public void setup() throws Exception {\n    classStream =\n        ProbeLoaderNewTest.class.getResourceAsStream(\"/resources/classdata/OnMethodTest.btrc\");\n  }\n\n  @Test\n  public void testPersistedProbeLoad() throws Exception {\n    BTraceProbe bp;\n    long t1 = System.nanoTime();\n    try {\n      bp = BPF.createProbe(classStream);\n    } finally {\n      System.err.println(\"# Creating probe took: \" + (System.nanoTime() - t1) + \"ns\");\n    }\n    Assertions.assertNotNull(bp);\n    Assertions.assertNotNull(bp.getClassName());\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/ProbeLoaderOldTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport java.io.InputStream;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.SharedSettings;\n\npublic class ProbeLoaderOldTest {\n  private static BTraceProbeFactory BPF;\n  private InputStream classStream;\n  private byte[] defData;\n\n  @BeforeAll\n  public static void setupClass() throws Exception {\n    BPF = new BTraceProbeFactory(SharedSettings.GLOBAL);\n  }\n\n  @BeforeEach\n  public void setup() throws Exception {\n    classStream =\n        ProbeLoaderOldTest.class.getResourceAsStream(\"/resources/classdata/TraceScript.clazz\");\n  }\n\n  @Test\n  public void testPersistedProbeLoad() throws Exception {\n    BTraceProbe bp;\n    long t1 = System.nanoTime();\n    try {\n      bp = BPF.createProbe(classStream);\n    } finally {\n      System.err.println(\"# Creating probe took: \" + (System.nanoTime() - t1) + \"ns\");\n    }\n    Assertions.assertNotNull(bp);\n    Assertions.assertNotNull(bp.getClassName());\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/ProbeLoaderUpgradeTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.management.ManagementFactory;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.openjdk.btrace.runtime.BTraceRuntimes;\n\npublic class ProbeLoaderUpgradeTest {\n  private static BTraceProbeFactory BPF;\n  private InputStream classStream;\n  private byte[] defData;\n\n  @BeforeAll\n  public static void setupClass() throws Exception {\n    BPF = new BTraceProbeFactory(SharedSettings.GLOBAL);\n  }\n\n  @BeforeEach\n  public void setup() throws Exception {\n    classStream =\n        ProbeLoaderUpgradeTest.class.getResourceAsStream(\"/resources/classdata/PackVersion1.btrc\");\n  }\n\n  @Test\n  public void testPersistedProbeLoad() throws Exception {\n    System.err.println(\"=== \" + ManagementFactory.getRuntimeMXBean().getInputArguments());\n    BTraceRuntime.Impl rt =\n        BTraceRuntimes.getRuntime(\n            \"PackVersion1\",\n            new ArgsMap(),\n            new CommandListener() {\n              @Override\n              public void onCommand(Command cmd) throws IOException {}\n            },\n            null);\n\n    BTraceProbe bp;\n    long t1 = System.nanoTime();\n    try {\n      bp = BPF.createProbe(classStream);\n    } finally {\n      System.err.println(\"# Creating probe took: \" + (System.nanoTime() - t1) + \"ns\");\n    }\n    Assertions.assertNotNull(bp);\n    Assertions.assertNotNull(bp.getClassName());\n\n    String fullAsm = InstrumentorTestBase.asmify(bp.getFullBytecode());\n    String bootstrapAsm = InstrumentorTestBase.asmify(bp.getDataHolderBytecode());\n\n    Assertions.assertFalse(fullAsm.contains(\"com/sun/btrace\"));\n    Assertions.assertFalse(bootstrapAsm.contains(\"com/sun/btrace\"));\n\n    InstrumentorTestBase.loadCode(\"PackVersion1\", bp.getFullBytecode());\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/StackTrackingMethodVisitorTest.java",
    "content": "/*\n * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.instr;\n\nimport java.io.IOException;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic class StackTrackingMethodVisitorTest extends InstrumentorTestBase {\n  private ClassReader reader;\n\n  @BeforeAll\n  public static void setUpClass() {}\n\n  @AfterAll\n  public static void tearDownClass() {}\n\n  @BeforeEach\n  public void setUp() throws IOException {\n    byte[] data = loadTargetClass(\"StackTrackerTest\");\n    System.err.println(asmify(data));\n    reader = new ClassReader(data);\n  }\n\n  @AfterEach\n  @Override\n  public void tearDown() {}\n\n  @Test\n  public void sanityTrackerTest() throws Exception {\n    // just make sure that a sufficiently complex methods won't cause\n    // any problems for tracking the stack\n    reader.accept(\n        new ClassVisitor(Opcodes.ASM9) {\n          private String clzName;\n\n          @Override\n          public void visit(\n              int i, int i1, String className, String string1, String string2, String[] strings) {\n            this.clzName = className;\n            super.visit(i, i1, className, string1, string2, strings);\n          }\n\n          @Override\n          public MethodVisitor visitMethod(\n              int access, String name, String desc, String sig, String[] exceptions) {\n            MethodVisitor mv = super.visitMethod(access, name, desc, sig, exceptions);\n            return new StackTrackingMethodVisitor(\n                mv, clzName, desc, ((access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC));\n          }\n        },\n        ClassReader.EXPAND_FRAMES);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/org/openjdk/btrace/instr/VariableMapperTest.java",
    "content": "package org.openjdk.btrace.instr;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.objectweb.asm.Label;\n\npublic class VariableMapperTest {\n  private VariableMapper instance;\n\n  @BeforeEach\n  public void setup() {\n    instance = new VariableMapper(0);\n  }\n\n  @Test\n  public void remapMethodArguments() {\n    int numArgs = 4;\n    VariableMapper mapper = new VariableMapper(numArgs);\n\n    assertEquals(0, mapper.remap(0, 1));\n    assertEquals(1, mapper.remap(1, 2));\n    assertEquals(3, mapper.remap(3, 1));\n  }\n\n  @Test\n  public void remapOutOfOrder() {\n    assertEquals(0, instance.remap(2, 1));\n    assertEquals(1, instance.remap(0, 2));\n    assertEquals(3, instance.remap(3, 1));\n  }\n\n  @Test\n  public void remapSame() {\n    int var = instance.remap(2, 1);\n    assertEquals(var, instance.remap(2, 1));\n  }\n\n  @Test\n  public void remapWithNewVar() {\n    int xVar = instance.newVarIdx(2);\n    int yVar = instance.newVarIdx(1);\n\n    assertEquals(VariableMapper.unmask(xVar), instance.remap(xVar, 2));\n    assertEquals(VariableMapper.unmask(yVar), instance.remap(yVar, 1));\n    assertEquals(3, instance.remap(0, 1));\n    assertEquals(4, instance.remap(1, 2));\n  }\n\n  @Test\n  public void remapOverflow() {\n    assertEquals(\n        0,\n        instance.remap(\n            16, 1)); // default mapping array size is 8 so going for double should trigger overflow\n    // handling\n  }\n\n  @Test\n  public void testMapEmpty() {\n    InstrumentationException ex =\n        assertThrows(InstrumentationException.class, () -> instance.map(0));\n    assertTrue(\n        ex.getMessage().contains(\"out of bounds\") || ex.getMessage().contains(\"not remapped\"));\n  }\n\n  @Test\n  public void testMapMethodArgs() {\n    int numArgs = 4;\n    VariableMapper mapper = new VariableMapper(numArgs);\n\n    assertEquals(0, mapper.map(0));\n    assertEquals(1, mapper.map(1));\n    assertEquals(3, mapper.map(3));\n  }\n\n  @Test\n  public void testMappings() {\n    instance.setMapping(0, 2 | VariableMapper.REMAP_FLAG, 1);\n    instance.setMapping(1, VariableMapper.REMAP_FLAG | VariableMapper.DOUBLE_SLOT_FLAG, 2);\n\n    assertEquals(2, instance.map(0));\n    assertEquals(0, instance.map(1));\n  }\n\n  @Test\n  public void testMapRemapped() {\n    int varX = instance.newVarIdx(1);\n    assertEquals(VariableMapper.unmask(varX), instance.map(varX));\n  }\n\n  @Test\n  public void mapOverflow() {\n    // default mapping array size is now larger, so going beyond it should trigger\n    // overflow handling with exception\n    InstrumentationException ex =\n        assertThrows(InstrumentationException.class, () -> instance.map(100));\n    assertTrue(ex.getMessage().contains(\"out of bounds\"));\n  }\n\n  @Test\n  void testRemapDoublesAndSingles() {\n    assertEquals(0, instance.remap(0, 1));\n    assertEquals(1, instance.remap(1, 2));\n    assertEquals(3, instance.remap(3, 2));\n    assertEquals(5, instance.remap(5, 1));\n    assertEquals(6, instance.remap(6, 1));\n\n    assertEquals(1, instance.remap(1, 1)); // change slot 1 to single-slot value\n    assertEquals(2, instance.remap(2, 1)); // 1 slot value should fit easily\n\n    assertEquals(7, instance.remap(5, 2)); // can't overwrite slot 6\n\n    assertEquals(9, instance.remap(4, 1)); // can not write to the double-slot-extension\n    assertEquals(3, instance.remap(3, 1)); // change slot 3 to single-slot value\n    assertEquals(4, instance.remap(4, 1)); // and suddenly the slot 4 is free to grab\n  }\n\n  @Test\n  void testScopedMappings() {\n    Label l1 = new Label();\n    Label l2 = new Label();\n    instance.noteLabel(l1);\n    instance.remap(0, 1); // 0\n    instance.remap(1, 2); // 1\n    // although the l1-scope is not finished yet we must be able to get the mapping\n    assertEquals(0, instance.map(0, l1));\n\n    instance.noteLabel(l2);\n    instance.remap(0, 2); // 3\n\n    assertEquals(0, instance.map(0, l1));\n    assertEquals(3, instance.map(0, l2));\n    assertEquals(3, instance.map(0));\n  }\n\n  @Test\n  void testScopedMappingsWithNewVars() {\n    Label l1 = new Label();\n    Label l2 = new Label();\n    instance.noteLabel(l1);\n    instance.remap(0, 1); // 0\n    instance.newVarIdx(1); // 1\n    instance.remap(1, 2); // 2\n  // although the l1-scope is not finished yet we must be able to get the mapping\n    assertEquals(0, instance.map(0, l1));\n    instance.noteLabel(l2);\n    instance.remap(0, 2); // 4\n\n    assertEquals(0, instance.map(0, l1));\n    assertEquals(4, instance.map(0, l2));\n    assertEquals(4, instance.map(0));\n  }\n\n  @Test\n  void testBug() {\n    Label l0 = new Label();\n    Label l5 = new Label();\n    Label l10 = new Label();\n    Label l22 = new Label();\n    Label l34 = new Label();\n    Label l55 = new Label();\n    Label l77 = new Label();\n    Label l99 = new Label();\n    Label l110 = new Label();\n    VariableMapper vm = new VariableMapper(2);\n\n    vm.noteLabel(l0);\n    assertEquals(0, vm.remap(0, 1));\n    vm.noteLabel(l5);\n    assertEquals(2, vm.remap(2, 1));\n    assertEquals(1, vm.remap(1, 1));\n    vm.noteLabel(l10);\n    assertEquals(3, vm.remap(3, 1));\n    vm.noteLabel(l22);\n    assertEquals(4, vm.remap(4, 1));\n    vm.noteLabel(l34);\n    assertEquals(5, vm.remap(5, 1));\n    vm.noteLabel(l55);\n    assertEquals(6, vm.remap(5, 2));\n    vm.noteLabel(l77);\n    assertEquals(8, vm.remap(4, 2));\n    vm.noteLabel(l99);\n    assertEquals(10, vm.remap(6, 1));\n    vm.noteLabel(l110);\n    assertEquals(11, vm.remap(6, 2));\n  }\n\n  @Test\n  public void testMapOutOfBoundsWithContext() {\n    InstrumentationException ex =\n        assertThrows(InstrumentationException.class, () -> instance.map(100));\n    assertTrue(ex.getMessage().contains(\"var=100\"));\n    assertTrue(ex.getMessage().contains(\"offset=\"));\n    assertTrue(ex.getMessage().contains(\"mappingSize=\"));\n  }\n\n  @Test\n  public void testMapUnmappedVariable() {\n    // Set up a variable that exists but isn't remapped\n    VariableMapper mapper = new VariableMapper(2);\n    // Remap variable 2 (first local), then try to map it back\n    // without having set the REMAP_FLAG\n    mapper.remap(2, 1); // This should create a mapping\n\n    // Now try to map a variable that's beyond what we've set up\n    InstrumentationException ex =\n        assertThrows(InstrumentationException.class, () -> mapper.map(3));\n    assertTrue(ex.getMessage().contains(\"not remapped\") || ex.getMessage().contains(\"out of bounds\"));\n  }\n\n  @Test\n  public void testExceptionMessageFormat() {\n    InstrumentationException ex =\n        assertThrows(InstrumentationException.class, () -> instance.map(50));\n\n    // Verify message contains all key debug fields\n    String msg = ex.getMessage();\n    assertTrue(msg.matches(\".*var=\\\\d+.*\"), \"Should contain var field\");\n    assertTrue(msg.matches(\".*offset=\\\\d+.*\"), \"Should contain offset field\");\n    assertTrue(msg.matches(\".*mappingSize=\\\\d+.*\"), \"Should contain mappingSize field\");\n    assertTrue(msg.matches(\".*argsSize=\\\\d+.*\"), \"Should contain argsSize field\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/AbstractClass.java",
    "content": "/*\n * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage resources;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author Jaroslav Bachorik jaroslav.bachorik@sun.com\n */\npublic abstract class AbstractClass {\n  protected AbstractClass(List lst) {}\n\n  public abstract void doGet(String a, Map b);\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/DerivedClass.java",
    "content": "/*\n * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage resources;\n\nimport java.util.ArrayList;\nimport java.util.Map;\n\n/**\n * @author Jaroslav Bachorik jaroslav.bachorik@sun.com\n */\npublic class DerivedClass extends AbstractClass {\n  private static volatile String defaultString;\n\n  static {\n    final String name = AbstractClass.class.getName();\n    try {\n      defaultString = \"value1\";\n    } catch (Throwable t1) {\n      try {\n        defaultString = \"value2\";\n      } catch (Throwable t2) {\n        defaultString = \"value3\";\n      }\n    }\n\n    defaultString = \"value4\";\n  }\n\n  public DerivedClass() {\n    super(new ArrayList());\n  }\n\n  @Override\n  public void doGet(String a, Map b) {\n    System.err.println(a);\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/InterestingVarsClass.java",
    "content": "package resources;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Iterator;\n\npublic class InterestingVarsClass {\n  public static class Token<T> {\n    public boolean getKind() {\n      return true;\n    }\n  }\n\n  public static void initAndStartApp(String a, String b, String c) {\n    Collection<Token<String>> tokens = tokens();\n    for (Token<?> token : tokens) {\n      System.out.println(token);\n    }\n\n    StringBuilder nextVar = new StringBuilder(a);\n    nextVar.append(b);\n\n    Iterator<Token<String>> iter = tokens.iterator();\n    while (iter.hasNext()) {\n      Token<?> token = iter.next();\n      if (token.getKind()) {\n        iter.remove();\n      }\n    }\n  }\n\n  private static Collection<Token<String>> tokens() {\n    return Arrays.asList(new Token<String>());\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/Main.java",
    "content": "/*\n * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage resources;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic class Main extends TestApp {\n  private String id = \"xxx\";\n\n  public static void main(String[] args) throws Exception {\n    Main i = new Main();\n    i.start();\n  }\n\n  @Override\n  protected void startWork() {\n    while (!Thread.currentThread().isInterrupted() && !finished.get()) {\n      callA();\n      try {\n        Thread.sleep(200);\n      } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n      }\n    }\n    Thread.currentThread().interrupt();\n  }\n\n  private void callA() {\n    print(\"i=\" + callB(1, \"Hello World\"));\n  }\n\n  private int callB(int i, String s) {\n    print(\"[\" + i + \"] = \" + s);\n    return i + 1;\n  }\n\n  @Override\n  public void print(String msg) {\n    System.out.println(msg);\n    System.out.flush();\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/OnMethodTest.java",
    "content": "/*\n * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage resources;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * !!! Only append the new methods; line numbers need to be kept intact !!!\n *\n * @author Jaroslav Bachorik\n */\n@org.openjdk.btrace.core.annotations.BTrace\npublic class OnMethodTest {\n  private int field;\n\n  public OnMethodTest() {\n    syncLock = new Object();\n  }\n\n  private OnMethodTest(String a) {\n    syncLock = new Object();\n  }\n\n  @org.openjdk.btrace.core.annotations.Level\n  public void noargs() {}\n  ;\n\n  public static void noargs$static() {}\n  ;\n\n  public long args(String a, long b, String[] c, int[] d) {\n    return 0L;\n  }\n\n  public static long args$static(String a, long b, String[] c, int[] d) {\n    return 0L;\n  }\n\n  public static long callTopLevelStatic(String a, long b) {\n    OnMethodTest instance = new OnMethodTest();\n    return callTargetStatic(a, b) + instance.callTarget(a, b);\n  }\n\n  public static long callTargetStatic(String a, long b) {\n    return 3L;\n  }\n\n  public long callTopLevel(String a, long b) {\n    return callTarget(a, b) + callTargetStatic(a, b);\n  }\n\n  private long callTarget(String a, long b) {\n    return 4L;\n  }\n\n  public void exception() {\n    try {\n      throw new IOException(\"hello world\");\n    } catch (IOException e) {\n      e.printStackTrace();\n    }\n  }\n\n  public void uncaught() {\n    throw new RuntimeException(\"ho-hey\");\n  }\n\n  public void array(int a) {\n    int[] arr = new int[10];\n\n    int b = arr[a];\n    arr[a] = 15;\n  }\n\n  public void field() {\n    this.field = this.field + 1;\n  }\n\n  public void newObject() {\n    Map<String, String> m = new HashMap<String, String>();\n  }\n\n  public void newArray() {\n    int[] a = new int[1];\n    int[][] b = new int[1][1];\n    String[] c = new String[1];\n    String[][] d = new String[1][1];\n  }\n\n  public void casts() {\n    Map<String, String> c = new HashMap<String, String>();\n    HashMap<String, String> d = (HashMap<String, String>) c;\n\n    if (c instanceof HashMap) {\n      System.err.println(\"hey ho\");\n    }\n  }\n\n  public void sync() {\n    synchronized (this) {\n      System.err.println(\"ho hey\");\n    }\n  }\n\n  public long callTopLevel1(String a, long b) {\n    long i = callTarget(a, b) + callTargetStatic(a, b);\n    return i + calLTargetX(a, b);\n  }\n\n  private long calLTargetX(String a, long b) {\n    return 5L;\n  }\n\n  public long argsMultiReturn(String a, long b, String[] c, int[] d) {\n    if (System.currentTimeMillis() > 325723059) {\n      return 0L;\n    }\n\n    if (System.currentTimeMillis() > 32525) {\n      return 1L;\n    }\n\n    {\n      System.out.println(\"fdsfg\");\n      return -1L;\n    }\n  }\n\n  public native long nativeWithReturn(int a, String b, long[] c, Object[] d);\n\n  public native void nativeWithoutReturn(int a, String b, long[] c, Object[] d);\n\n  private static long sField;\n\n  public void staticField() {\n    OnMethodTest.sField += 1;\n  }\n\n  public void syncM() {\n    synchronized (syncLock) {\n      System.err.println(\"ho hey\");\n    }\n  }\n\n  private final Object syncLock;\n\n  public String argsTypeMatch(java.util.ArrayList<String> l) {\n    return \"x\";\n  }\n\n  public void caught() {\n    try {\n      throw new RuntimeException(\"ho-hey\");\n    } catch (RuntimeException e) {\n      e.printStackTrace();\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/StackTrackerTest.java",
    "content": "/*\n * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage resources;\n\npublic class StackTrackerTest {\n  private static String testStatic(int a, Class<?> clz) {\n    int i = 10;\n\n    try {\n      int j = i + 10;\n      if (j > 10) {\n        consumeInt(j - 10);\n      } else {\n        consumeInt(j);\n      }\n      int x = 0;\n      out:\n      while (x++ < 10) {\n        consumeInt(x);\n        for (int z = x; z >= 0; z--) {\n          consumeInt(x);\n          if (convertInt(z) == 1L) {\n            break out;\n          }\n        }\n      }\n      return \"ok\";\n    } catch (Throwable l) {\n\n    }\n\n    return \"fail\";\n  }\n\n  private static void consumeInt(int x) {\n    System.out.println(x);\n  }\n\n  private static long convertInt(int x) {\n    return x + 1;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/TestApp.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage resources;\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic abstract class TestApp implements TestPrinter {\n  protected final AtomicBoolean finished = new AtomicBoolean(false);\n\n  public final void start() throws Exception {\n    Thread t =\n        new Thread(\n            new Runnable() {\n              @Override\n              public void run() {\n                startWork();\n              }\n            },\n            \"Worker Thread\");\n    System.out.println(\"ready:\" + getPID());\n    System.out.flush();\n    t.setDaemon(true);\n    t.start();\n\n    do {\n      String resp =\n          new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)).readLine();\n      System.out.println(\"Received \" + resp + \" - \" + \"done\".contains(resp));\n      if (\"done\".contains(resp)) {\n        System.out.flush();\n        System.out.println(System.currentTimeMillis() + \":  Interrupting the worker thread\");\n        finished.set(true);\n        System.out.println(\n            System.currentTimeMillis() + \": Waiting for the worker thread to finish\");\n        t.join(1000);\n        if (t.isAlive()) {\n          Thread.dumpStack();\n          throw new RuntimeException(\"Dangling worker thread\");\n        }\n        System.out.println(System.currentTimeMillis() + \": Worker thread finished\");\n        break;\n      }\n    } while (true);\n  }\n\n  private static long getPID() {\n    String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();\n    return Long.parseLong(processName.split(\"@\")[0]);\n  }\n\n  /** The work here should be done repeatedly until the thread gets interrupted */\n  protected abstract void startWork();\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/TestPrinter.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage resources;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic interface TestPrinter {\n  void print(String msg);\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/issues/BTRACE106.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage resources.issues;\n\n/**\n * @author Jaroslav Bachorik <jaroslav.bachorik@oracle.com>\n */\n@Deprecated\npublic class BTRACE106 {\n  private void aMethod() {\n    System.out.println(\"A Method\");\n  }\n\n  @Deprecated\n  private void bMethod() {\n    System.out.println(\"B Method\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/issues/BTRACE22.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage resources.issues;\n\n/**\n * @author Jaroslav Bachorik jaroslav.bachorik@sun.com\n */\npublic class BTRACE22 {\n  public double testDouble() {\n    double d = 12.4325 * 11.842;\n    System.err.println(d);\n    return d;\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/issues/BTRACE256.java",
    "content": "package resources.issues;\n\npublic class BTRACE256 {\n  public java.util.Random r = new java.util.Random(System.currentTimeMillis());\n\n  public static void main(String[] args) throws Exception {\n\n    Thread t =\n        new Thread(\n            new Runnable() {\n              @Override\n              public void run() {\n                BTRACE256 test = new BTRACE256();\n                try {\n                  while (true) {\n                    test.doStuff();\n                  }\n                } catch (Exception e) {\n                }\n              }\n            });\n\n    t.start();\n    t.join();\n  }\n\n  public void doStuff() throws Exception {\n    Thread.sleep(r.nextInt(2000));\n    System.out.print(\".\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/issues/BTRACE28.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage resources.issues;\n\n/**\n * @author Jaroslav Bachorik jaroslav.bachorik@sun.com\n */\npublic class BTRACE28 {\n  private void serveResource(String param1, String param2) {\n    String resourceType = \"resourceType\";\n    String contentType = \"contentType\";\n    int indice, tempIndice;\n    byte[] tempArr;\n    byte[] mainArr = new byte[0];\n    byte[] byteArr = new byte[65535];\n\n    StringBuilder sb = new StringBuilder();\n\n    try {\n      sb.append(\"hooo\");\n      System.err.println(\"i am here\");\n    } catch (Throwable e) {\n      e.printStackTrace();\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/java/resources/issues/BTRACE87.java",
    "content": "/*\n * To change this template, choose Tools | Templates\n * and open the template in the editor.\n */\npackage resources.issues;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author Jaroslav Bachorik <jaroslav.bachorik@oracle.com>\n */\npublic class BTRACE87 {\n  private void containerMethod() {\n    List a = new ArrayList();\n    a.clear();\n    a.add(\"sample\");\n  }\n}\n"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/ExportTest",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ExportTest$testArgs(Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ExportTest\"\n]\nFRAME SAME\nMAXSTACK = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/OnProbeTest",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/OnTimerTest",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/ServicesTest",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"resources.OnMethodTest\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ServicesTest$testFieldInjection(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ServicesTest\"\n]\nFRAME SAME\nMAXSTACK = 1"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/TLSTest",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TLSTest$testArgs(Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TLSTest\"\n]\nFRAME SAME\nMAXSTACK = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/TraceAllTest",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLDC \"public void resources.OnMethodTest#<init>\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME FULL [resources/OnMethodTest] []\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLDC \"private void resources.OnMethodTest#<init>(java.lang.String)\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME FULL [resources/OnMethodTest java/lang/String] []\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public void resources.OnMethodTest#noargs\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nMAXSTACK = 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public static void resources.OnMethodTest#noargs$static\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nMAXSTACK = 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public long resources.OnMethodTest#args(java.lang.String, long, java.lang.String[], int[])\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public static long resources.OnMethodTest#args$static(java.lang.String, long, java.lang.String[], int[])\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public static long resources.OnMethodTest#callTopLevelStatic(java.lang.String, long)\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public static long resources.OnMethodTest#callTargetStatic(java.lang.String, long)\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public long resources.OnMethodTest#callTopLevel(java.lang.String, long)\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"private long resources.OnMethodTest#callTarget(java.lang.String, long)\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public void resources.OnMethodTest#exception\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public void resources.OnMethodTest#uncaught\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public void resources.OnMethodTest#array(int)\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public void resources.OnMethodTest#field\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public void resources.OnMethodTest#newObject\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public void resources.OnMethodTest#newArray\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public void resources.OnMethodTest#casts\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nLDC \"public void resources.OnMethodTest#sync\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public long resources.OnMethodTest#callTopLevel1(java.lang.String, long)\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"private long resources.OnMethodTest#calLTargetX(java.lang.String, long)\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public long resources.OnMethodTest#argsMultiReturn(java.lang.String, long, java.lang.String[], int[])\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public void resources.OnMethodTest#staticField\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nLDC \"public void resources.OnMethodTest#syncM\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public java.lang.String resources.OnMethodTest#argsTypeMatch(java.util.ArrayList)\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public void resources.OnMethodTest#caught\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TraceAllTest$doall(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TraceAllTest\"\n]\nFRAME SAME"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/issues/BTRACE106",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nLDC \"aMethod\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE106$o1(Ljava/lang/Object;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE106\"\n]\nFRAME SAME\nLCONST_0\nLSTORE 1\nLCONST_0\nLSTORE 3\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 3\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 3\nLSUB\nLSTORE 1\nL2\nFRAME APPEND [J J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"bMethod\"\nLLOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE106$o3(Ljava/lang/Object;Ljava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE106\"\n]\nL3\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLDC \"bMethod\"\nLLOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE106$o2(Ljava/lang/Object;Ljava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE106\"\n]\nL4\nFRAME SAME\nL5\nLOCALVARIABLE this Lresources/issues/BTRACE106; L0 L5 0\nMAXSTACK = 4\nMAXLOCALS = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/issues/BTRACE189",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/issues/BTRACE22",
    "content": "LCONST_0\nLSTORE 1\nLCONST_0\nLSTORE 3\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 3\nDSTORE 5\nDLOAD 5\nDLOAD 5\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 3\nLSUB\nLSTORE 1\nL3\nFRAME FULL [resources/issues/BTRACE22 J J D] [D]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLLOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE22$tracker(Ljava/lang/Object;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE22\"\n]\nL4\nFRAME SAME1 D\nL5\nLOCALVARIABLE this Lresources/issues/BTRACE22; L0 L5 0\nLOCALVARIABLE d D L1 L5 5\nMAXSTACK = 6\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/issues/BTRACE256",
    "content": "LCONST_0\nLSTORE 1\nLCONST_0\nLSTORE 3\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public void resources.issues.BTRACE256#doStuff\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE256$entry(Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE256\"\n]\nFRAME APPEND [J J]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 3\nLSUB\nLSTORE 1\nL3\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nLDC \"public void resources.issues.BTRACE256#doStuff\"\nLLOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE256$exit(Ljava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE256\"\n]\nL4\nFRAME SAME\nL5\nLOCALVARIABLE this Lresources/issues/BTRACE256; L0 L5 0\nMAXSTACK = 4\nMAXLOCALS = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/issues/BTRACE28",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLDC \"resources.issues.BTRACE28\"\nLDC \"<init>\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE28$tracker(Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE28\"\n]\nL1\nFRAME FULL [resources/issues/BTRACE28] []\nL2\nLOCALVARIABLE this Lresources/issues/BTRACE28; L0 L2 0\nMAXSTACK = 2\nASTORE 5\nASTORE 6\nASTORE 7\nALOAD 7\nFRAME FULL [resources/issues/BTRACE28 java/lang/String java/lang/String java/lang/String java/lang/String [B [B java/lang/StringBuilder] [java/lang/Throwable]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L11\nLDC \"resources.issues.BTRACE28\"\nLDC \"serveResource\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE28$tracker(Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE28\"\n]\nL11\nFRAME SAME\nL12\nLOCALVARIABLE this Lresources/issues/BTRACE28; L3 L12 0\nLOCALVARIABLE param1 Ljava/lang/String; L3 L12 1\nLOCALVARIABLE param2 Ljava/lang/String; L3 L12 2\nLOCALVARIABLE resourceType Ljava/lang/String; L4 L12 3\nLOCALVARIABLE contentType Ljava/lang/String; L5 L12 4\nLOCALVARIABLE mainArr [B L6 L12 5\nLOCALVARIABLE byteArr [B L7 L12 6\nLOCALVARIABLE sb Ljava/lang/StringBuilder; L0 L12 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/issues/BTRACE53",
    "content": "LCONST_0\nLSTORE 1\nLCONST_0\nLSTORE 3\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 3\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 3\nLSUB\nLSTORE 1\nL2\nFRAME FULL [resources/DerivedClass J J] []\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nLLOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE53$onInit(J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE53\"\n]\nL3\nFRAME SAME\nL4\nLOCALVARIABLE this Lresources/DerivedClass; L0 L4 0\nMAXSTACK = 4\nMAXLOCALS = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/issues/BTRACE69",
    "content": "TRYCATCHBLOCK L4 L5 L5 java/lang/Throwable\nTRYCATCHBLOCK L4 L6 L6 java/lang/Throwable\nDUP\nASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE69$onSyncEntry(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE69\"\n]\nFRAME APPEND [resources/OnMethodTest resources/OnMethodTest]\nL7\nLINENUMBER 127 L7\nDUP\nASTORE 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L8\nALOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE69$onSyncExit(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE69\"\n]\nL8\nFRAME FULL [resources/OnMethodTest resources/OnMethodTest resources/OnMethodTest resources/OnMethodTest] [resources/OnMethodTest]\nGOTO L9\nFRAME FULL [resources/OnMethodTest java/lang/Object resources/OnMethodTest] [java/lang/Throwable]\nASTORE 4\nDUP\nASTORE 5\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L10\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE69$onSyncExit(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE69\"\n]\nL10\nFRAME FULL [resources/OnMethodTest java/lang/Object resources/OnMethodTest T java/lang/Throwable java/lang/Object] [java/lang/Object]\nALOAD 4\nATHROW\nL9\nLINENUMBER 128 L9\nFRAME FULL [resources/OnMethodTest T resources/OnMethodTest resources/OnMethodTest] []\nRETURN\nL5\nFRAME FULL [resources/OnMethodTest] [java/lang/Throwable]\nFRAME SAME1 java/lang/Throwable\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L4 L5 0\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/issues/BTRACE87",
    "content": "ASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"containerMethod\"\nICONST_0\nANEWARRAY java/lang/Object\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE87$o(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE87\"\n]\nL2\nFRAME APPEND [java/util/ArrayList java/util/ArrayList]\nALOAD 2\nL3\nLINENUMBER 17 L3\nASTORE 3\nASTORE 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLDC \"containerMethod\"\nICONST_1\nANEWARRAY java/lang/Object\nDUP\nICONST_0\nALOAD 3\nAASTORE\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$BTRACE87$o(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/BTRACE87\"\n]\nL4\nFRAME APPEND [java/lang/String java/util/ArrayList]\nALOAD 4\nALOAD 3\nL5\nLINENUMBER 18 L5\nL6\nLOCALVARIABLE this Lresources/issues/BTRACE87; L0 L6 0\nLOCALVARIABLE a Ljava/util/List; L1 L6 1\nMAXSTACK = 6\nMAXLOCALS = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/issues/BTRACE_333",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/issues/InterestingVarsTest",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$InterestingVarsTest$entry(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/InterestingVarsTest\"\n]\nFRAME SAME"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/issues/TezSplitter",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nICONST_4\nANEWARRAY java/lang/Object\nDUP\nICONST_0\nALOAD 1\nAASTORE\nDUP\nICONST_1\nALOAD 2\nAASTORE\nDUP\nICONST_2\nILOAD 3\nINVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\nAASTORE\nDUP\nICONST_3\nALOAD 4\nAASTORE\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TezSplitter$getGroupedSplitsHook([Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TezSplitter\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nICONST_5\nANEWARRAY java/lang/Object\nDUP\nICONST_0\nALOAD 1\nAASTORE\nDUP\nICONST_1\nALOAD 2\nAASTORE\nDUP\nICONST_2\nILOAD 3\nINVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\nAASTORE\nDUP\nICONST_3\nALOAD 4\nAASTORE\nDUP\nICONST_4\nALOAD 5\nAASTORE\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$TezSplitter$getGroupedSplitsHook([Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/TezSplitter\"\n]\nFRAME SAME\nLSTORE 23\nLSTORE 25\nLSTORE 27\nLLOAD 25\nLLOAD 27\nLLOAD 27\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map I T T T T T T T T J J J] []\nLLOAD 25\nLLOAD 27\nLLOAD 23\nLLOAD 25\nLLOAD 25\nLLOAD 23\nLLOAD 25\nLLOAD 23\nLLOAD 27\nLLOAD 27\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map I T T T T T T I T J J J] []\nLLOAD 23\nLLOAD 27\nISTORE 23\nASTORE 24\nALOAD 24\nISTORE 25\nISTORE 26\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map [Lorg/apache/hadoop/mapred/InputSplit; T T T T T T T T I [Lorg/apache/hadoop/mapred/InputSplit; I I] []\nILOAD 26\nILOAD 25\nALOAD 24\nILOAD 26\nASTORE 27\nALOAD 27\nASTORE 28\nALOAD 28\nALOAD 27\nILOAD 23\nIINC 23 1\nALOAD 28\nIINC 26 1\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map] []\nLSTORE 23\nISTORE 25\nILOAD 25\nISTORE 26\nISTORE 27\nASTORE 28\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T T T J I I I java/util/Iterator] []\nALOAD 28\nALOAD 28\nILOAD 26\nASTORE 28\nISTORE 29\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T [Lorg/apache/hadoop/mapred/InputSplit; I J I I I java/util/Set I] []\nILOAD 29\nILOAD 29\nASTORE 30\nALOAD 28\nALOAD 30\nASTORE 31\nALOAD 30\nASTORE 32\nALOAD 32\nALOAD 32\nASTORE 32\nALOAD 32\nASTORE 33\nALOAD 33\nISTORE 34\nISTORE 35\nILOAD 35\nILOAD 34\nALOAD 33\nILOAD 35\nASTORE 36\nALOAD 36\nASTORE 36\nALOAD 28\nALOAD 36\nIINC 35 1\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T [Lorg/apache/hadoop/mapred/InputSplit; I J I I I java/util/Set I org/apache/hadoop/mapred/InputSplit org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder [Ljava/lang/String;] []\nALOAD 28\nASTORE 33\nALOAD 33\nALOAD 33\nASTORE 34\nALOAD 34\nASTORE 35\nALOAD 35\nALOAD 31\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T [Lorg/apache/hadoop/mapred/InputSplit; I J I I I java/util/Set I] []\nIINC 29 1\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T T T J I I I java/util/Set] []\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set] []\nLLOAD 23\nILOAD 25\nILOAD 26\nILOAD 27\nISTORE 29\nILOAD 27\nASTORE 30\nASTORE 31\nISTORE 32\nISTORE 33\nISTORE 34\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I] []\nILOAD 29\nIINC 34 1\nISTORE 35\nASTORE 36\nALOAD 36\nALOAD 36\nASTORE 37\nALOAD 30\nALOAD 31\nALOAD 37\nASTORE 38\nALOAD 37\nASTORE 39\nALOAD 39\nASTORE 40\nALOAD 40\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I java/util/Iterator java/util/Map$Entry java/lang/String org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$LocationHolder org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder] []\nALOAD 39\nISTORE 41\nLSTORE 42\nISTORE 44\nALOAD 30\nALOAD 40\nLLOAD 42\nALOAD 40\nLSTORE 42\nIINC 44 1\nALOAD 39\nALOAD 39\nASTORE 40\nALOAD 40\nLLOAD 42\nALOAD 40\nLLOAD 23\nILOAD 44\nILOAD 27\nALOAD 39\nILOAD 32\nLLOAD 42\nLLOAD 23\nILOAD 44\nILOAD 27\nALOAD 39\nILOAD 41\nIINC 35 1\nALOAD 38\nASTORE 45\nALOAD 38\nASTORE 45\nILOAD 33\nALOAD 30\nASTORE 46\nALOAD 46\nALOAD 46\nASTORE 47\nALOAD 47\nASTORE 48\nALOAD 48\nALOAD 48\nASTORE 49\nALOAD 49\nISTORE 50\nISTORE 51\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I java/util/Iterator java/util/Map$Entry java/lang/String org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$LocationHolder org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder I J I [Ljava/lang/String; java/util/Iterator org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder [Ljava/lang/String; [Ljava/lang/String; I I] []\nILOAD 51\nILOAD 50\nALOAD 49\nILOAD 51\nASTORE 52\nALOAD 52\nALOAD 31\nALOAD 52\nIINC 51 1\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I java/util/Iterator java/util/Map$Entry java/lang/String org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$LocationHolder org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder I J I [Ljava/lang/String; java/util/Iterator] []\nALOAD 31\nALOAD 45\nASTORE 45\nALOAD 30\nALOAD 45\nILOAD 33\nALOAD 38\nALOAD 38\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I java/util/Iterator java/util/Map$Entry java/lang/String org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$LocationHolder org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder I J I [Ljava/lang/String;] [L144 L144 I java/lang/String [Ljava/lang/String;]\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I java/util/Iterator java/util/Map$Entry java/lang/String org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$LocationHolder org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder I J I [Ljava/lang/String;] [L144 L144 I java/lang/String [Ljava/lang/String; java/lang/String]\nASTORE 46\nALOAD 30\nASTORE 47\nALOAD 47\nALOAD 47\nASTORE 48\nALOAD 46\nALOAD 48\nALOAD 48\nALOAD 38\nALOAD 48\nIINC 29 1\nALOAD 30\nALOAD 46\nALOAD 38\nALOAD 46\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I] []\nILOAD 33\nILOAD 35\nISTORE 33\nILOAD 29\nISTORE 36\nILOAD 36\nASTORE 37\nASTORE 38\nALOAD 38\nALOAD 38\nASTORE 39\nALOAD 39\nASTORE 40\nALOAD 40\nALOAD 40\nASTORE 41\nALOAD 41\nALOAD 37\nALOAD 41\nALOAD 40\nALOAD 37\nILOAD 36\nILOAD 36\nALOAD 37\nASTORE 38\nASTORE 39\nASTORE 40\nALOAD 40\nALOAD 40\nASTORE 41\nASTORE 42\nALOAD 41\nALOAD 41\nASTORE 42\nALOAD 38\nALOAD 41\nALOAD 42\nALOAD 39\nALOAD 42\nALOAD 39\nALOAD 42\nILOAD 36\nALOAD 39\nASTORE 40\nALOAD 37\nISTORE 41\nASTORE 42\nALOAD 42\nISTORE 43\nISTORE 44\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I I java/util/Set java/util/Map java/util/Map java/util/HashSet I [Lorg/apache/hadoop/mapred/InputSplit; I I] []\nILOAD 44\nILOAD 43\nALOAD 42\nILOAD 44\nASTORE 45\nILOAD 41\nALOAD 37\nALOAD 45\nIINC 41 -1\nALOAD 40\nALOAD 45\nASTORE 46\nALOAD 45\nASTORE 47\nALOAD 47\nALOAD 47\nASTORE 47\nALOAD 47\nASTORE 48\nALOAD 48\nISTORE 49\nISTORE 50\nILOAD 50\nILOAD 49\nALOAD 48\nILOAD 50\nASTORE 51\nALOAD 51\nASTORE 51\nALOAD 40\nALOAD 38\nALOAD 51\nIINC 50 1\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I I java/util/Set java/util/Map java/util/Map java/util/HashSet I [Lorg/apache/hadoop/mapred/InputSplit; I I org/apache/hadoop/mapred/InputSplit org/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder [Ljava/lang/String;] []\nALOAD 40\nASTORE 48\nALOAD 48\nALOAD 48\nASTORE 49\nALOAD 39\nALOAD 49\nALOAD 46\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I I java/util/Set java/util/Map java/util/Map java/util/HashSet I [Lorg/apache/hadoop/mapred/InputSplit; I I] []\nIINC 44 1\nALOAD 37\nALOAD 39\nFSTORE 42\nFLOAD 42\nLLOAD 23\nFLOAD 42\nLSTORE 53\nILOAD 27\nFLOAD 42\nISTORE 45\nLLOAD 55\nLLOAD 55\nLSTORE 23\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I I java/util/Set java/util/Map java/util/Map java/util/HashSet I F T T I T T T T T T T T T J] []\nILOAD 45\nILOAD 45\nISTORE 27\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I I java/util/Set java/util/Map java/util/Map java/util/HashSet I F] []\nILOAD 34\nILOAD 29\nILOAD 35\nLLOAD 23\nILOAD 27\nFRAME FULL [org/apache/hadoop/mapred/split/TezMapredSplitsGrouper org/apache/hadoop/conf/Configuration [Lorg/apache/hadoop/mapred/InputSplit; I java/lang/String org/apache/hadoop/mapred/split/SplitSizeEstimator I java/lang/String java/lang/String [Ljava/lang/String; I J java/util/Map java/util/List T T T T T T I I J I I I java/util/Set I java/util/List java/util/Set I I I I] []\nILOAD 32\nILOAD 35\nILOAD 25\nISTORE 32\nILOAD 34\nILOAD 29\nILOAD 35\nILOAD 34\nILOAD 29\nILOAD 35\nASTORE 35\nALOAD 35\nILOAD 29\nALOAD 35\nLOCALVARIABLE lengthPerGroup J L42 L34 23\nLOCALVARIABLE maxLengthPerGroup J L43 L34 25\nLOCALVARIABLE minLengthPerGroup J L44 L34 27\nLOCALVARIABLE newSplit Lorg/apache/hadoop/mapred/split/TezGroupedSplit; L68 L70 28\nLOCALVARIABLE split Lorg/apache/hadoop/mapred/InputSplit; L66 L70 27\nLOCALVARIABLE i I L63 L60 23\nLOCALVARIABLE location Ljava/lang/String; L91 L94 36\nLOCALVARIABLE holder Lorg/apache/hadoop/mapred/split/TezMapredSplitsGrouper$LocationHolder; L98 L99 35\nLOCALVARIABLE location Ljava/lang/String; L97 L99 34\nLOCALVARIABLE splitHolder Lorg/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder; L85 L96 31\nLOCALVARIABLE locations [Ljava/lang/String; L86 L96 32\nLOCALVARIABLE split Lorg/apache/hadoop/mapred/InputSplit; L83 L96 30\nLOCALVARIABLE loc Ljava/lang/String; L153 L154 52\nLOCALVARIABLE locations [Ljava/lang/String; L149 L150 48\nLOCALVARIABLE splitH Lorg/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder; L148 L150 47\nLOCALVARIABLE groupedSplitHolder Lorg/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder; L162 L168 48\nLOCALVARIABLE location Ljava/lang/String; L120 L173 38\nLOCALVARIABLE holder Lorg/apache/hadoop/mapred/split/TezMapredSplitsGrouper$LocationHolder; L121 L173 39\nLOCALVARIABLE splitHolder Lorg/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder; L122 L173 40\nLOCALVARIABLE oldHeadIndex I L125 L173 41\nLOCALVARIABLE groupLength J L126 L173 42\nLOCALVARIABLE groupNumSplits I L127 L173 44\nLOCALVARIABLE groupLocation [Ljava/lang/String; L141 L173 45\nLOCALVARIABLE groupedSplit Lorg/apache/hadoop/mapred/split/TezGroupedSplit; L159 L173 46\nLOCALVARIABLE entry Ljava/util/Map$Entry; L117 L173 37\nLOCALVARIABLE splitHolder Lorg/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder; L185 L186 41\nLOCALVARIABLE locHolder Lorg/apache/hadoop/mapred/split/TezMapredSplitsGrouper$LocationHolder; L182 L183 40\nLOCALVARIABLE entry Ljava/util/Map$Entry; L181 L183 39\nLOCALVARIABLE rack Ljava/lang/String; L198 L202 42\nLOCALVARIABLE location Ljava/lang/String; L197 L202 41\nLOCALVARIABLE location Ljava/lang/String; L223 L226 51\nLOCALVARIABLE rack Ljava/lang/String; L228 L229 49\nLOCALVARIABLE splitHolder Lorg/apache/hadoop/mapred/split/TezMapredSplitsGrouper$SplitHolder; L217 L214 46\nLOCALVARIABLE locations [Ljava/lang/String; L218 L214 47\nLOCALVARIABLE split Lorg/apache/hadoop/mapred/InputSplit; L209 L214 45\nLOCALVARIABLE newLengthPerGroup J L235 L233 43\nLOCALVARIABLE newNumSplitsInGroup I L236 L233 45\nLOCALVARIABLE numRemainingSplits I L177 L174 36\nLOCALVARIABLE remainingSplits Ljava/util/Set; L178 L174 37\nLOCALVARIABLE locToRackMap Ljava/util/Map; L193 L174 38\nLOCALVARIABLE rackLocations Ljava/util/Map; L194 L174 39\nLOCALVARIABLE rackSet Ljava/util/HashSet; L205 L174 40\nLOCALVARIABLE numRackSplitsToGroup I L206 L174 41\nLOCALVARIABLE rackSplitReduction F L232 L174 42\nLOCALVARIABLE numFullGroupsCreated I L114 L248 35\nLOCALVARIABLE lengthPerGroup J L72 L257 23\nLOCALVARIABLE numNodeLocations I L73 L257 25\nLOCALVARIABLE numSplitsPerLocation I L74 L257 26\nLOCALVARIABLE numSplitsInGroup I L75 L257 27\nLOCALVARIABLE locSet Ljava/util/Set; L80 L257 28\nLOCALVARIABLE splitsProcessed I L105 L257 29\nLOCALVARIABLE group Ljava/util/List; L106 L257 30\nLOCALVARIABLE groupLocationSet Ljava/util/Set; L107 L257 31\nLOCALVARIABLE allowSmallGroups Z L108 L257 32\nLOCALVARIABLE doingRackLocal Z L109 L257 33\nLOCALVARIABLE iterations I L110 L257 34\nLOCALVARIABLE groupedSplits [Lorg/apache/hadoop/mapred/InputSplit; L252 L257 35\nMAXLOCALS = 57"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/AllLines",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"<init>\"\nLDC 41\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nFRAME FULL [resources/OnMethodTest] []\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nLDC \"<init>\"\nLDC 42\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL2\nFRAME SAME\nALOAD 0\nL3\nLINENUMBER 43 L3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLDC \"<init>\"\nLDC 43\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL4\nFRAME SAME\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"<init>\"\nLDC 45\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nFRAME FULL [resources/OnMethodTest java/lang/String] []\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nLDC \"<init>\"\nLDC 46\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL2\nFRAME SAME\nALOAD 0\nL3\nLINENUMBER 47 L3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLDC \"<init>\"\nLDC 47\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL4\nFRAME SAME\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a Ljava/lang/String; L0 L5 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"noargs\"\nLDC 50\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nACONST_NULL\nLDC \"noargs$static\"\nLDC 53\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"args\"\nLDC 57\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nACONST_NULL\nLDC \"args$static\"\nLDC 61\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLOCALVARIABLE a Ljava/lang/String; L0 L2 0\nLOCALVARIABLE b J L0 L2 1\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 3\nLOCALVARIABLE d [I L0 L2 4\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nACONST_NULL\nLDC \"callTopLevelStatic\"\nLDC 65\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLINENUMBER 66 L2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nACONST_NULL\nLDC \"callTopLevelStatic\"\nLDC 66\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL3\nFRAME APPEND [resources/OnMethodTest]\nL4\nLOCALVARIABLE a Ljava/lang/String; L0 L4 0\nLOCALVARIABLE b J L0 L4 1\nLOCALVARIABLE instance Lresources/OnMethodTest; L2 L4 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nACONST_NULL\nLDC \"callTargetStatic\"\nLDC 70\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLOCALVARIABLE a Ljava/lang/String; L0 L2 0\nLOCALVARIABLE b J L0 L2 1\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLDC \"callTopLevel\"\nLDC 74\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nALOAD 0\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"callTarget\"\nLDC 78\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"exception\"\nLDC 83\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL2\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"exception\"\nLDC 84\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL3\nFRAME SAME1 java/lang/Throwable\nL4\nLINENUMBER 85 L4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nALOAD 0\nLDC \"exception\"\nLDC 85\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL5\nFRAME APPEND [java/lang/Throwable]\nL6\nLINENUMBER 87 L6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L7\nALOAD 0\nLDC \"exception\"\nLDC 87\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL7\nFRAME SAME\nL8\nLOCALVARIABLE e Ljava/io/IOException; L4 L6 1\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L8 0\nMAXSTACK = 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"uncaught\"\nLDC 90\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"array\"\nLDC 94\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLINENUMBER 96 L2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"array\"\nLDC 96\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL3\nFRAME APPEND [[I]\nL4\nLINENUMBER 97 L4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nALOAD 0\nLDC \"array\"\nLDC 97\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL5\nFRAME APPEND [I]\nL6\nLINENUMBER 98 L6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L7\nALOAD 0\nLDC \"array\"\nLDC 98\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL7\nFRAME SAME\nL8\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L8 0\nLOCALVARIABLE a I L0 L8 1\nLOCALVARIABLE arr [I L2 L8 2\nLOCALVARIABLE b I L4 L8 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLDC \"field\"\nLDC 101\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nALOAD 0\nL2\nLINENUMBER 102 L2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"field\"\nLDC 102\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL3\nFRAME SAME\nL4\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L4 0\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"newObject\"\nLDC 105\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLINENUMBER 106 L2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"newObject\"\nLDC 106\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL3\nFRAME APPEND [java/util/HashMap]\nL4\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L4 0\nLOCALVARIABLE m Ljava/util/Map; L2 L4 1\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"newArray\"\nLDC 109\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLINENUMBER 110 L2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"newArray\"\nLDC 110\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL3\nFRAME APPEND [[I]\nL4\nLINENUMBER 111 L4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nALOAD 0\nLDC \"newArray\"\nLDC 111\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL5\nFRAME APPEND [[[I]\nL6\nLINENUMBER 112 L6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L7\nALOAD 0\nLDC \"newArray\"\nLDC 112\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL7\nFRAME APPEND [[Ljava/lang/String;]\nL8\nLINENUMBER 113 L8\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L9\nALOAD 0\nLDC \"newArray\"\nLDC 113\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL9\nFRAME APPEND [[[Ljava/lang/String;]\nL10\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L10 0\nLOCALVARIABLE a [I L2 L10 1\nLOCALVARIABLE b [[I L4 L10 2\nLOCALVARIABLE c [Ljava/lang/String; L6 L10 3\nLOCALVARIABLE d [[Ljava/lang/String; L8 L10 4\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"casts\"\nLDC 116\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLINENUMBER 117 L2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"casts\"\nLDC 117\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL3\nFRAME APPEND [java/util/HashMap]\nL4\nLINENUMBER 119 L4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nALOAD 0\nLDC \"casts\"\nLDC 119\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL5\nFRAME APPEND [java/util/HashMap]\nIFEQ L6\nL7\nLINENUMBER 120 L7\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L8\nALOAD 0\nLDC \"casts\"\nLDC 120\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL8\nFRAME SAME\nL6\nLINENUMBER 122 L6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L9\nALOAD 0\nLDC \"casts\"\nLDC 122\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL9\nFRAME SAME\nL10\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L10 0\nLOCALVARIABLE c Ljava/util/Map; L2 L10 1\nLOCALVARIABLE d Ljava/util/HashMap; L4 L10 2\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nLDC \"sync\"\nLDC 125\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL5\nFRAME SAME\nALOAD 0\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L6\nALOAD 0\nLDC \"sync\"\nLDC 126\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL6\nFRAME APPEND [resources/OnMethodTest]\nL7\nLINENUMBER 127 L7\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L8\nALOAD 0\nLDC \"sync\"\nLDC 127\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL8\nFRAME SAME\nGOTO L9\nL9\nLINENUMBER 128 L9\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L10\nALOAD 0\nLDC \"sync\"\nLDC 128\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL10\nFRAME FULL [resources/OnMethodTest resources/OnMethodTest] []\nL11\nLOCALVARIABLE this Lresources/OnMethodTest; L4 L11 0\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLDC \"callTopLevel1\"\nLDC 131\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nALOAD 0\nL2\nLINENUMBER 132 L2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"callTopLevel1\"\nLDC 132\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL3\nFRAME APPEND [J]\nL4\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L4 0\nLOCALVARIABLE a Ljava/lang/String; L0 L4 1\nLOCALVARIABLE b J L0 L4 2\nLOCALVARIABLE i J L2 L4 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"calLTargetX\"\nLDC 136\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"argsMultiReturn\"\nLDC 140\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nIFLE L2\nL3\nLINENUMBER 141 L3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLDC \"argsMultiReturn\"\nLDC 141\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL4\nFRAME SAME\nL2\nLINENUMBER 144 L2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nALOAD 0\nLDC \"argsMultiReturn\"\nLDC 144\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL5\nIFLE L6\nL7\nLINENUMBER 145 L7\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L8\nALOAD 0\nLDC \"argsMultiReturn\"\nLDC 145\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL8\nFRAME SAME\nL6\nLINENUMBER 149 L6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L9\nALOAD 0\nLDC \"argsMultiReturn\"\nLDC 149\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL9\nL10\nLINENUMBER 150 L10\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L11\nALOAD 0\nLDC \"argsMultiReturn\"\nLDC 150\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL11\nFRAME SAME\nL12\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L12 0\nLOCALVARIABLE a Ljava/lang/String; L0 L12 1\nLOCALVARIABLE b J L0 L12 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L12 4\nLOCALVARIABLE d [I L0 L12 5\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"staticField\"\nLDC 161\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLINENUMBER 162 L2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"staticField\"\nLDC 162\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL3\nFRAME SAME\nL4\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L4 0\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nLDC \"syncM\"\nLDC 165\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL5\nFRAME SAME\nALOAD 0\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L6\nALOAD 0\nLDC \"syncM\"\nLDC 166\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL6\nFRAME APPEND [java/lang/Object]\nL7\nLINENUMBER 167 L7\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L8\nALOAD 0\nLDC \"syncM\"\nLDC 167\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL8\nFRAME SAME\nGOTO L9\nFRAME SAME1 java/lang/Throwable\nL9\nLINENUMBER 168 L9\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L10\nALOAD 0\nLDC \"syncM\"\nLDC 168\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL10\nFRAME SAME\nL11\nLOCALVARIABLE this Lresources/OnMethodTest; L4 L11 0\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"argsTypeMatch\"\nLDC 173\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL1\nFRAME SAME\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE l Ljava/util/ArrayList; L0 L2 1\nMAXSTACK = 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"caught\"\nLDC 178\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL2\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"caught\"\nLDC 179\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL3\nFRAME SAME1 java/lang/Throwable\nL4\nLINENUMBER 180 L4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nALOAD 0\nLDC \"caught\"\nLDC 180\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL5\nFRAME APPEND [java/lang/Throwable]\nL6\nLINENUMBER 182 L6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L7\nALOAD 0\nLDC \"caught\"\nLDC 182\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AllLines$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AllLines\"\n]\nL7\nFRAME SAME\nL8\nLOCALVARIABLE e Ljava/lang/RuntimeException; L4 L6 1\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L8 0\nMAXSTACK = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/AnytypeArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nICONST_4\nANEWARRAY java/lang/Object\nDUP\nICONST_0\nALOAD 1\nAASTORE\nDUP\nICONST_1\nLLOAD 2\nINVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;\nAASTORE\nDUP\nICONST_2\nALOAD 4\nAASTORE\nDUP\nICONST_3\nALOAD 5\nAASTORE\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AnytypeArgs$args(Ljava/lang/Object;[Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AnytypeArgs\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/AnytypeArgsNoSelf",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nICONST_4\nANEWARRAY java/lang/Object\nDUP\nICONST_0\nALOAD 1\nAASTORE\nDUP\nICONST_1\nLLOAD 2\nINVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;\nAASTORE\nDUP\nICONST_2\nALOAD 4\nAASTORE\nDUP\nICONST_3\nALOAD 5\nAASTORE\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AnytypeArgsNoSelf$argsNoSelf([Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AnytypeArgsNoSelf\"\n]\nFRAME SAME\nMAXSTACK = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/Args",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Args$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Args\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/Args2Sampled",
    "content": "ICONST_0\nISTORE 6\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hit (I)Z\nISTORE 6\nILOAD 6\nIFEQ L0\nL1\nFRAME APPEND [I]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Args2Sampled$args2(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Args2Sampled\"\n]\nFRAME SAME\nILOAD 6\nIFEQ L2\nL3\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Args2Sampled$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Args2Sampled\"\n]\nL2\nLINENUMBER 57 L2\nFRAME SAME\nL4\nLOCALVARIABLE this Lresources/OnMethodTest; L2 L4 0\nLOCALVARIABLE a Ljava/lang/String; L2 L4 1\nLOCALVARIABLE b J L2 L4 2\nLOCALVARIABLE c [Ljava/lang/String; L2 L4 4\nLOCALVARIABLE d [I L2 L4 5\nMAXSTACK = 6\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsDuration",
    "content": "LCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nDUP2\nLSTORE 10\nALOAD 0\nLLOAD 10\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration\"\n]\nL2\nFRAME SAME1 J\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L3 4\nLOCALVARIABLE d [I L0 L3 5\nMAXSTACK = 12\nMAXLOCALS = 12"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsDuration2",
    "content": "LCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nDUP2\nLSTORE 10\nALOAD 0\nLLOAD 10\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2$args2(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2\"\n]\nL2\nFRAME SAME1 J\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nDUP2\nLSTORE 12\nALOAD 0\nLLOAD 12\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2\"\n]\nL3\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J T T] [J]\nL4\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L4 0\nLOCALVARIABLE a Ljava/lang/String; L0 L4 1\nLOCALVARIABLE b J L0 L4 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L4 4\nLOCALVARIABLE d [I L0 L4 5\nMAXSTACK = 12\nMAXLOCALS = 14"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsDuration2Err",
    "content": "TRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nTRYCATCHBLOCK L0 L2 L2 java/lang/Throwable\nLCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 8\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nDUP\nASTORE 10\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLLOAD 6\nALOAD 10\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2Err$args2(Ljava/lang/Object;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2Err\"\n]\nL3\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J java/lang/Throwable] [java/lang/Throwable]\nATHROW\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nDUP\nASTORE 11\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLLOAD 6\nALOAD 11\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2Err$args(Ljava/lang/Object;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2Err\"\n]\nL4\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J T java/lang/Throwable] [java/lang/Throwable]\nATHROW\nMAXSTACK = 5\nMAXLOCALS = 12"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsDuration2Sampled",
    "content": "LCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nICONST_0\nISTORE 10\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitTimed (I)J\nDUP2\nLSTORE 8\nL2I\nISTORE 10\nILOAD 10\nIFEQ L1\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.getEndTs (I)J\nLLOAD 8\nLSUB\nLSTORE 6\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J I] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 11\nALOAD 0\nLLOAD 11\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2Sampled$args2(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2Sampled\"\n]\nL1\nFRAME SAME1 J\nILOAD 10\nIFEQ L3\nL4\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J I T T] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nDUP2\nLSTORE 13\nALOAD 0\nLLOAD 13\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2Sampled$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2Sampled\"\n]\nL3\nFRAME SAME1 J\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a Ljava/lang/String; L0 L5 1\nLOCALVARIABLE b J L0 L5 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L5 4\nLOCALVARIABLE d [I L0 L5 5\nMAXSTACK = 12\nMAXLOCALS = 15"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsDurationBoxed",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsDurationBoxedErr",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsDurationConstructor",
    "content": "LCONST_0\nLSTORE 2\nLCONST_0\nLSTORE 4\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 4\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 4\nLSUB\nLSTORE 2\nL3\nFRAME FULL [resources/OnMethodTest java/lang/String J J] []\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLLOAD 2\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationConstructor$args(Ljava/lang/Object;JLjava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationConstructor\"\n]\nL4\nFRAME SAME\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a Ljava/lang/String; L0 L5 1\nMAXSTACK = 4\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsDurationConstructorErr",
    "content": "TRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nL2\nLINENUMBER 41 L2\nLCONST_0\nLSTORE 1\nLCONST_0\nLSTORE 3\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 3\nL0\nLINENUMBER 42 L0\nL3\nLINENUMBER 43 L3\nL1\nFRAME FULL [resources/OnMethodTest J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 3\nLSUB\nLSTORE 1\nDUP\nASTORE 5\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLLOAD 1\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationConstructorErr$args(Ljava/lang/Object;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationConstructorErr\"\n]\nL4\nFRAME FULL [resources/OnMethodTest J J java/lang/Throwable] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L2 L1 0\nMAXSTACK = 5\nMAXLOCALS = 6\nTRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nL2\nLINENUMBER 45 L2\nLCONST_0\nLSTORE 2\nLCONST_0\nLSTORE 4\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 4\nL0\nLINENUMBER 46 L0\nL3\nLINENUMBER 47 L3\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 4\nLSUB\nLSTORE 2\nDUP\nASTORE 6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLLOAD 2\nALOAD 6\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationConstructorErr$args(Ljava/lang/Object;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationConstructorErr\"\n]\nL4\nFRAME FULL [resources/OnMethodTest java/lang/String J J java/lang/Throwable] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L2 L1 0\nLOCALVARIABLE a Ljava/lang/String; L2 L1 1\nMAXSTACK = 5\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsDurationErr",
    "content": "TRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nLCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 8\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nDUP\nASTORE 10\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLLOAD 6\nALOAD 10\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationErr$args(Ljava/lang/Object;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationErr\"\n]\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J java/lang/Throwable] [java/lang/Throwable]\nATHROW\nMAXSTACK = 5\nMAXLOCALS = 11"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsDurationMultiReturn",
    "content": "LCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nL3\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nDUP2\nLSTORE 10\nALOAD 0\nLLOAD 10\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationMultiReturn$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationMultiReturn\"\n]\nL4\nFRAME SAME1 J\nIFLE L5\nL6\nLINENUMBER 145 L6\nL7\nFRAME SAME1 J\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L8\nDUP2\nLSTORE 12\nALOAD 0\nLLOAD 12\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationMultiReturn$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationMultiReturn\"\n]\nL8\nFRAME SAME1 J\nL5\nLINENUMBER 149 L5\nL9\nLINENUMBER 150 L9\nL10\nFRAME SAME1 J\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L11\nDUP2\nLSTORE 14\nALOAD 0\nLLOAD 14\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationMultiReturn$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationMultiReturn\"\n]\nL11\nFRAME SAME1 J\nL12\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L12 0\nLOCALVARIABLE a Ljava/lang/String; L0 L12 1\nLOCALVARIABLE b J L0 L12 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L12 4\nLOCALVARIABLE d [I L0 L12 5\nMAXSTACK = 12\nMAXLOCALS = 16"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsDurationSampled",
    "content": "LCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nICONST_0\nISTORE 10\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitTimed (I)J\nDUP2\nLSTORE 8\nL2I\nISTORE 10\nILOAD 10\nIFEQ L1\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.getEndTs (I)J\nLLOAD 8\nLSUB\nLSTORE 6\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J I] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 11\nALOAD 0\nLLOAD 11\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationSampled$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationSampled\"\n]\nL1\nFRAME SAME1 J\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L3 4\nLOCALVARIABLE d [I L0 L3 5\nMAXSTACK = 12\nMAXLOCALS = 13"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsNoSelf",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public long resources.OnMethodTest#args(java.lang.String, long, java.lang.String[], int[])\"\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsNoSelf$argsNoSelf(Ljava/lang/String;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsNoSelf\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsReturn",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 6\nALOAD 0\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsReturn$args(Ljava/lang/Object;JLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsReturn\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 10\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsReturnAugmented",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLSTORE 6\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nLLOAD 6\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsReturnAugmented$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[IJ)J [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsReturnAugmented\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 8\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsReturnAugmented1",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLSTORE 6\nALOAD 0\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsReturnAugmented1$args(Ljava/lang/Object;JLjava/lang/String;J[Ljava/lang/String;[I)J [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsReturnAugmented1\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 8\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsReturnBoxed",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 6\nALOAD 0\nLLOAD 6\nINVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsReturnBoxed$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsReturnBoxed\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 9\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsReturnSampled",
    "content": "ICONST_0\nISTORE 6\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hit (I)Z\nISTORE 6\nILOAD 6\nIFEQ L1\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I I] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 7\nALOAD 0\nLLOAD 7\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsReturnSampled$args(Ljava/lang/Object;JLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsReturnSampled\"\n]\nL1\nFRAME SAME1 J\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L3 4\nLOCALVARIABLE d [I L0 L3 5\nMAXSTACK = 10\nMAXLOCALS = 9"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsReturnTypeMatch",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 6\nALOAD 0\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsReturnTypeMatch$args(Ljava/lang/Object;JLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsReturnTypeMatch\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 10\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsReturnTypeNoMatch",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsReturnVoid",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nACONST_NULL\nASTORE 1\nALOAD 0\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsReturnVoid$args(Ljava/lang/Object;Ljava/lang/Void;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsReturnVoid\"\n]\nL1\nFRAME SAME\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nMAXSTACK = 2\nMAXLOCALS = 2"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsSampled",
    "content": "ICONST_0\nISTORE 6\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hit (I)Z\nISTORE 6\nILOAD 6\nIFEQ L0\nL1\nFRAME APPEND [I]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsSampled$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsSampled\"\n]\nFRAME SAME\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 6\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsSampledAdaptive",
    "content": "ICONST_0\nISTORE 6\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitAdaptive (I)Z\nISTORE 6\nILOAD 6\nIFEQ L0\nL1\nFRAME APPEND [I]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsSampledAdaptive$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsSampledAdaptive\"\n]\nFRAME SAME\nILOAD 6\nIFEQ L2\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.updateEndTs (I)V\nL2\nFRAME SAME1 J\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L3 4\nLOCALVARIABLE d [I L0 L3 5\nMAXSTACK = 6\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsSampledNoSampling",
    "content": "ICONST_0\nISTORE 6\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hit (I)Z\nISTORE 6\nILOAD 6\nIFEQ L0\nL1\nFRAME APPEND [I]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsSampledNoSampling$argsSampled(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsSampledNoSampling\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsSampledNoSampling$argsNoSampling(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsSampledNoSampling\"\n]\nL2\nLINENUMBER 57 L2\nFRAME SAME\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L2 L3 0\nLOCALVARIABLE a Ljava/lang/String; L2 L3 1\nLOCALVARIABLE b J L2 L3 2\nLOCALVARIABLE c [Ljava/lang/String; L2 L3 4\nLOCALVARIABLE d [I L2 L3 5\nMAXSTACK = 6\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsShared",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsShared$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsShared\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsSigMatch",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsSigMatch$m3(Ljava/lang/Object;Ljava/util/ArrayList;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsSigMatch\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsSigMatch$m1(Ljava/lang/Object;Ljava/util/List;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsSigMatch\"\n]\nL1\nLINENUMBER 173 L1\nFRAME SAME\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L1 L2 0\nLOCALVARIABLE l Ljava/util/ArrayList; L1 L2 1\nMAXSTACK = 2"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArgsUnsafe",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsUnsafe$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsUnsafe\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArrayGetAfter",
    "content": "DUP2\nISTORE 3\nASTORE 4\nDUP\nISTORE 5\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nILOAD 5\nALOAD 4\nILOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArrayGetAfter$args(Ljava/lang/Object;I[II)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArrayGetAfter\"\n]\nFRAME FULL [resources/OnMethodTest I [I I [I I] [I]\nISTORE 6\nL3\nLINENUMBER 97 L3\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L3 L5 6\nMAXSTACK = 5\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArrayGetAfterAny",
    "content": "DUP2\nISTORE 3\nASTORE 4\nDUP\nISTORE 5\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nILOAD 5\nINVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\nALOAD 4\nILOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArrayGetAfterAny$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArrayGetAfterAny\"\n]\nFRAME FULL [resources/OnMethodTest I [I I [I I] [I]\nISTORE 6\nL3\nLINENUMBER 97 L3\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L3 L5 6\nMAXSTACK = 5\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArrayGetBefore",
    "content": "DUP2\nASTORE 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nALOAD 4\nILOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArrayGetBefore$args(Ljava/lang/Object;[II)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArrayGetBefore\"\n]\nFRAME FULL [resources/OnMethodTest I [I I [I] [[I I]\nIALOAD\nISTORE 5\nL3\nLINENUMBER 97 L3\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L3 L5 5\nMAXSTACK = 5\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArrayGetBeforeAny",
    "content": "DUP2\nASTORE 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nALOAD 4\nILOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArrayGetBeforeAny$args(Ljava/lang/Object;Ljava/lang/Object;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArrayGetBeforeAny\"\n]\nFRAME FULL [resources/OnMethodTest I [I I [I] [[I I]\nIALOAD\nISTORE 5\nL3\nLINENUMBER 97 L3\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L3 L5 5\nMAXSTACK = 5\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArraySetAfter",
    "content": "ISTORE 4\nDUP2\nISTORE 5\nASTORE 6\nILOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nALOAD 6\nILOAD 5\nILOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArraySetAfter$args(Ljava/lang/Object;[III)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArraySetAfter\"\n]\nFRAME FULL [resources/OnMethodTest I [I I I I [I] []\nMAXSTACK = 4\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArraySetAfterAny",
    "content": "ISTORE 4\nDUP2\nISTORE 5\nASTORE 6\nILOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nALOAD 6\nILOAD 5\nILOAD 4\nINVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArraySetAfterAny$args(Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArraySetAfterAny\"\n]\nFRAME FULL [resources/OnMethodTest I [I I I I [I] []\nMAXSTACK = 4\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArraySetBefore",
    "content": "ISTORE 4\nDUP2\nISTORE 5\nASTORE 6\nILOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nALOAD 6\nILOAD 5\nILOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArraySetBefore$args(Ljava/lang/Object;[III)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArraySetBefore\"\n]\nL3\nFRAME FULL [resources/OnMethodTest I [I I I I [I] [[I I I]\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L2 L5 3\nMAXSTACK = 7\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ArraySetBeforeAny",
    "content": "ISTORE 4\nDUP2\nISTORE 5\nASTORE 6\nILOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nALOAD 6\nILOAD 5\nILOAD 4\nINVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArraySetBeforeAny$args(Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArraySetBeforeAny\"\n]\nL3\nFRAME FULL [resources/OnMethodTest I [I I I I [I] [[I I I]\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L2 L5 3\nMAXSTACK = 7\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/Catch",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Catch$args(Ljava/lang/Object;Ljava/io/IOException;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Catch\"\n]\nFRAME FULL [resources/OnMethodTest java/io/IOException] [java/io/IOException]\nASTORE 2\nL3\nLINENUMBER 85 L3\nALOAD 2\nL4\nLINENUMBER 87 L4\nL5\nLOCALVARIABLE e Ljava/io/IOException; L3 L4 2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/CheckcastAfter",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"casts\"\nALOAD 2\nLDC \"java.util.HashMap\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$CheckcastAfter$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/CheckcastAfter\"\n]\nFRAME FULL [resources/OnMethodTest java/util/HashMap java/util/HashMap] [java/util/HashMap]\nASTORE 3\nL3\nLINENUMBER 119 L3\nIFEQ L4\nL5\nLINENUMBER 120 L5\nL4\nLINENUMBER 122 L4\nFRAME FULL [resources/OnMethodTest java/util/Map java/util/HashMap java/util/HashMap] []\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE c Ljava/util/Map; L1 L6 1\nLOCALVARIABLE d Ljava/util/HashMap; L3 L6 3\nMAXSTACK = 5\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/CheckcastBefore",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"resources.OnMethodTest\"\nLDC \"java.util.HashMap\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$CheckcastBefore$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/CheckcastBefore\"\n]\nFRAME FULL [resources/OnMethodTest java/util/HashMap java/util/HashMap] [java/util/HashMap]\nCHECKCAST java/util/HashMap\nASTORE 3\nL3\nLINENUMBER 119 L3\nIFEQ L4\nL5\nLINENUMBER 120 L5\nL4\nLINENUMBER 122 L4\nFRAME FULL [resources/OnMethodTest java/util/Map java/util/HashMap java/util/HashMap] []\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE c Ljava/util/Map; L1 L6 1\nLOCALVARIABLE d Ljava/util/HashMap; L3 L6 3\nMAXSTACK = 5\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ConstructorArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ConstructorArgs$args(Ljava/lang/Object;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ConstructorArgs\"\n]\nFRAME FULL [resources/OnMethodTest java/lang/String] []"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/Error",
    "content": "TRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nFRAME SAME1 java/lang/Throwable\nDUP\nASTORE 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"uncaught\"\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Error$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Error\"\n]\nL2\nFRAME FULL [resources/OnMethodTest java/lang/Throwable] [java/lang/Throwable]\nATHROW\nMAXSTACK = 4\nMAXLOCALS = 2"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ErrorCaught",
    "content": "TRYCATCHBLOCK L0 L2 L2 java/lang/Throwable\nL3\nLINENUMBER 180 L3\nL4\nLINENUMBER 182 L4\nL2\nFRAME SAME1 java/lang/Throwable\nDUP\nASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nALOAD 0\nLDC \"caught\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ErrorCaught$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ErrorCaught\"\n]\nL5\nFRAME FULL [resources/OnMethodTest T java/lang/Throwable] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE e Ljava/lang/RuntimeException; L3 L4 1\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nMAXSTACK = 4\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/ErrorDuration",
    "content": "TRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nLCONST_0\nLSTORE 1\nLCONST_0\nLSTORE 3\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 3\nFRAME FULL [resources/OnMethodTest J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 3\nLSUB\nLSTORE 1\nDUP\nASTORE 5\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"uncaught\"\nLLOAD 1\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ErrorDuration$args(Ljava/lang/Object;Ljava/lang/String;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ErrorDuration\"\n]\nL2\nFRAME FULL [resources/OnMethodTest J J java/lang/Throwable] [java/lang/Throwable]\nATHROW\nMAXSTACK = 6\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/FieldGetAfter",
    "content": "DUP\nASTORE 1\nDUP\nISTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 1\nLDC \"field int resources.OnMethodTest#field\"\nILOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldGetAfter$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldGetAfter\"\n]\nL1\nFRAME FULL [resources/OnMethodTest resources/OnMethodTest I] [resources/OnMethodTest I]\nL2\nLINENUMBER 102 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nMAXSTACK = 6\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/FieldGetAfterStatic",
    "content": "DUP2\nLSTORE 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nACONST_NULL\nLDC \"static field long resources.OnMethodTest#sField\"\nLLOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldGetAfterStatic$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldGetAfterStatic\"\n]\nL1\nFRAME FULL [resources/OnMethodTest J] [J]\nL2\nLINENUMBER 162 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nMAXSTACK = 7\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/FieldGetBefore",
    "content": "DUP\nASTORE 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 1\nLDC \"field\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldGetBefore$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldGetBefore\"\n]\nL1\nFRAME FULL [resources/OnMethodTest resources/OnMethodTest] [resources/OnMethodTest resources/OnMethodTest]\nL2\nLINENUMBER 102 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nMAXSTACK = 5\nMAXLOCALS = 2"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/FieldGetBeforeStatic",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nACONST_NULL\nLDC \"sField\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldGetBeforeStatic$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldGetBeforeStatic\"\n]\nL1\nFRAME SAME\nL2\nLINENUMBER 162 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/FieldSetAfter",
    "content": "ISTORE 1\nDUP\nASTORE 2\nILOAD 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 2\nLDC \"field\"\nILOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldSetAfter$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldSetAfter\"\n]\nFRAME APPEND [I resources/OnMethodTest]\nMAXSTACK = 4\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/FieldSetAfterStatic",
    "content": "LSTORE 1\nLLOAD 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nACONST_NULL\nLDC \"sField\"\nLLOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldSetAfterStatic$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldSetAfterStatic\"\n]\nFRAME APPEND [J]\nMAXSTACK = 5\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/FieldSetBefore",
    "content": "ISTORE 1\nDUP\nASTORE 2\nILOAD 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 2\nLDC \"field\"\nILOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldSetBefore$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldSetBefore\"\n]\nL1\nFRAME FULL [resources/OnMethodTest I resources/OnMethodTest] [resources/OnMethodTest I]\nL2\nLINENUMBER 102 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nMAXSTACK = 6\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/FieldSetBeforeStatic",
    "content": "LSTORE 1\nLLOAD 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nACONST_NULL\nLDC \"sField\"\nLLOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldSetBeforeStatic$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldSetBeforeStatic\"\n]\nL1\nFRAME FULL [resources/OnMethodTest J] [J]\nL2\nLINENUMBER 162 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nMAXSTACK = 7\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/InstanceofAfter",
    "content": "DUP\nASTORE 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"casts\"\nLDC \"java.util.HashMap\"\nALOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$InstanceofAfter$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/InstanceofAfter\"\n]\nL3\nFRAME FULL [resources/OnMethodTest java/util/HashMap java/util/HashMap java/util/HashMap] [I]\nIFEQ L4\nL5\nLINENUMBER 120 L5\nL4\nLINENUMBER 122 L4\nFRAME FULL [resources/OnMethodTest java/util/Map java/util/HashMap java/util/HashMap] []\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE c Ljava/util/Map; L1 L6 1\nLOCALVARIABLE d Ljava/util/HashMap; L2 L6 2\nMAXSTACK = 5\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/InstanceofBefore",
    "content": "DUP\nASTORE 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"resources.OnMethodTest\"\nLDC \"java.util.HashMap\"\nALOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$InstanceofBefore$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/InstanceofBefore\"\n]\nL3\nFRAME FULL [resources/OnMethodTest java/util/HashMap java/util/HashMap java/util/HashMap] [java/util/HashMap]\nIFEQ L4\nL5\nLINENUMBER 120 L5\nL4\nLINENUMBER 122 L4\nFRAME FULL [resources/OnMethodTest java/util/Map java/util/HashMap java/util/HashMap] []\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE c Ljava/util/Map; L1 L6 1\nLOCALVARIABLE d Ljava/util/HashMap; L2 L6 2\nMAXSTACK = 5\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/Line",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"exception\"\nLDC 84\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Line$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Line\"\n]\nL2\nFRAME SAME1 java/lang/Throwable\nL3\nLINENUMBER 85 L3\nL4\nLINENUMBER 87 L4\nL5\nLOCALVARIABLE e Ljava/io/IOException; L3 L4 1\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nMAXSTACK = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MatchAnnotated",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MatchAnnotated$args(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MatchAnnotated\"\n]\nFRAME SAME\nMAXSTACK = 1"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MatchAnnotatedRegex",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MatchAnnotatedRegex$args(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MatchAnnotatedRegex\"\n]\nFRAME SAME\nMAXSTACK = 1"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MatchDerived",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MatchDerived$args(Lresources/AbstractClass;Ljava/lang/String;Ljava/util/Map;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MatchDerived\"\n]\nFRAME SAME\nMAXSTACK = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCall",
    "content": "LSTORE 4\nASTORE 6\nASTORE 7\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 6\nLLOAD 4\nALOAD 7\nLDC \"special long resources.OnMethodTest#callTarget(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevel\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCall$args(Ljava/lang/Object;Ljava/lang/String;JLjava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCall\"\n]\nL1\nFRAME APPEND [J java/lang/String resources/OnMethodTest]\nALOAD 7\nALOAD 6\nLLOAD 4\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 8\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCallDuration",
    "content": "LCONST_0\nLSTORE 4\nLCONST_0\nLSTORE 6\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 6\nLSTORE 8\nASTORE 10\nASTORE 11\nALOAD 11\nALOAD 10\nLLOAD 8\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 12\nLLOAD 12\nLCONST_0\nALOAD 10\nLLOAD 8\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDuration$args(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDuration\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J J J java/lang/String resources/OnMethodTest] [J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 9\nMAXLOCALS = 14"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCallDuration2",
    "content": "LCONST_0\nLSTORE 4\nLCONST_0\nLSTORE 6\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 6\nLSTORE 8\nASTORE 10\nASTORE 11\nALOAD 11\nALOAD 10\nLLOAD 8\nLCONST_0\nLSTORE 12\nLCONST_0\nLSTORE 14\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 14\nLSTORE 16\nASTORE 18\nASTORE 19\nALOAD 19\nALOAD 18\nLLOAD 16\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 20\nLLOAD 20\nLCONST_0\nALOAD 18\nLLOAD 16\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDuration2$args0(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDuration2\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J J J java/lang/String resources/OnMethodTest J J J java/lang/String resources/OnMethodTest] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nDUP2\nLSTORE 22\nLLOAD 22\nLCONST_0\nALOAD 10\nLLOAD 8\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDuration2$args1(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDuration2\"\n]\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J J J J java/lang/String resources/OnMethodTest J J J java/lang/String resources/OnMethodTest T T] [J]\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nMAXSTACK = 9\nMAXLOCALS = 24"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCallDurationSampled",
    "content": "LCONST_0\nLSTORE 4\nLCONST_0\nLSTORE 6\nICONST_0\nISTORE 8\nICONST_2\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitTimed (I)J\nDUP2\nLSTORE 6\nL2I\nISTORE 8\nLSTORE 9\nASTORE 11\nASTORE 12\nALOAD 12\nALOAD 11\nLLOAD 9\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 13\nLLOAD 13\nLCONST_0\nALOAD 11\nLLOAD 9\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDurationSampled$args(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDurationSampled\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J J I J java/lang/String resources/OnMethodTest] [J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 9\nMAXLOCALS = 15"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCallDurationSampledMulti",
    "content": "LCONST_0\nLSTORE 4\nLCONST_0\nLSTORE 6\nICONST_0\nISTORE 8\nICONST_2\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitTimed (I)J\nDUP2\nLSTORE 6\nL2I\nISTORE 8\nLSTORE 9\nASTORE 11\nASTORE 12\nALOAD 12\nALOAD 11\nLLOAD 9\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 13\nLLOAD 13\nLCONST_0\nALOAD 11\nLLOAD 9\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDurationSampledMulti$args(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDurationSampledMulti\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J J I J java/lang/String resources/OnMethodTest] [J]\nLCONST_0\nLSTORE 15\nLCONST_0\nLSTORE 17\nICONST_0\nISTORE 19\nICONST_3\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitTimed (I)J\nDUP2\nLSTORE 17\nL2I\nISTORE 19\nLSTORE 20\nASTORE 22\nALOAD 22\nLLOAD 20\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nDUP2\nLSTORE 23\nLLOAD 23\nLCONST_0\nALOAD 22\nLLOAD 20\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDurationSampledMulti$args(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDurationSampledMulti\"\n]\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J J J I J java/lang/String resources/OnMethodTest T T J J I J java/lang/String] [J J]\nLSTORE 25\nL3\nLINENUMBER 132 L3\nLLOAD 25\nL4\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L4 0\nLOCALVARIABLE a Ljava/lang/String; L0 L4 1\nLOCALVARIABLE b J L0 L4 2\nLOCALVARIABLE i J L3 L4 25\nMAXSTACK = 11\nMAXLOCALS = 27"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCallNoArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallNoArgs$args()V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallNoArgs\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J] [resources/OnMethodTest java/lang/String J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCallReturn",
    "content": "LSTORE 4\nASTORE 6\nASTORE 7\nALOAD 7\nALOAD 6\nLLOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 8\nLLOAD 8\nALOAD 6\nLLOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallReturn$args(JLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallReturn\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J java/lang/String resources/OnMethodTest] [J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 7\nMAXLOCALS = 10"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCallReturnAugmented",
    "content": "LSTORE 4\nASTORE 6\nASTORE 7\nALOAD 7\nALOAD 6\nLLOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLSTORE 8\nALOAD 6\nLLOAD 4\nLLOAD 8\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallReturnAugmented$args(Ljava/lang/String;JJ)J [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallReturnAugmented\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J java/lang/String resources/OnMethodTest] [J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXLOCALS = 10"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCallReturnAugmented1",
    "content": "LSTORE 4\nASTORE 6\nASTORE 7\nALOAD 7\nALOAD 6\nLLOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLSTORE 8\nLLOAD 8\nALOAD 6\nLLOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallReturnAugmented1$args(JLjava/lang/String;J)J [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallReturnAugmented1\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J java/lang/String resources/OnMethodTest] [J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXLOCALS = 10"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCallSampled",
    "content": "ICONST_0\nISTORE 4\nICONST_2\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hit (I)Z\nISTORE 4\nLSTORE 5\nASTORE 7\nASTORE 8\nILOAD 4\nIFEQ L1\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J I J java/lang/String resources/OnMethodTest] []\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 7\nLLOAD 5\nALOAD 8\nLDC \"special long resources.OnMethodTest#callTarget(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevel\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallSampled$args(Ljava/lang/Object;Ljava/lang/String;JLjava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallSampled\"\n]\nL1\nFRAME SAME\nALOAD 8\nALOAD 7\nLLOAD 5\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nMAXSTACK = 8\nMAXLOCALS = 9"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCallSampledAdaptive",
    "content": "ICONST_0\nISTORE 4\nICONST_2\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitAdaptive (I)Z\nISTORE 4\nLSTORE 5\nASTORE 7\nASTORE 8\nILOAD 4\nIFEQ L1\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J I J java/lang/String resources/OnMethodTest] []\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 7\nLLOAD 5\nALOAD 8\nLDC \"special long resources.OnMethodTest#callTarget(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevel\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallSampledAdaptive$args(Ljava/lang/Object;Ljava/lang/String;JLjava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallSampledAdaptive\"\n]\nL1\nFRAME SAME\nALOAD 8\nALOAD 7\nLLOAD 5\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nMAXSTACK = 8\nMAXLOCALS = 9"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/MethodCallStatic",
    "content": "LSTORE 4\nASTORE 6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 6\nLLOAD 4\nACONST_NULL\nLDC \"static long resources.OnMethodTest#callTargetStatic(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevel\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallStatic$args(Ljava/lang/Object;Ljava/lang/String;JLjava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallStatic\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J java/lang/String] [J]\nALOAD 6\nLLOAD 4\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 10\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/NativeWithReturn",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/NativeWithoutReturn",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/NewAfter",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 1\nLDC \"java.util.HashMap\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewAfter$args(Ljava/lang/Object;Ljava/util/Map;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewAfter\"\n]\nFRAME FULL [resources/OnMethodTest java/util/HashMap] [java/util/HashMap]\nASTORE 2\nL2\nLINENUMBER 106 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE m Ljava/util/Map; L2 L3 2\nMAXSTACK = 4\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/NewArrayIntAfter",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayIntAfter$args(Ljava/lang/Object;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayIntAfter\"\n]\nFRAME FULL [resources/OnMethodTest [I] [[I]\nASTORE 2\nL2\nLINENUMBER 110 L2\nASTORE 3\nL3\nLINENUMBER 111 L3\nASTORE 4\nL4\nLINENUMBER 112 L4\nASTORE 5\nL5\nLINENUMBER 113 L5\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE a [I L2 L6 2\nLOCALVARIABLE b [[I L3 L6 3\nLOCALVARIABLE c [Ljava/lang/String; L4 L6 4\nLOCALVARIABLE d [[Ljava/lang/String; L5 L6 5\nMAXSTACK = 3\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/NewArrayIntBefore",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"int\"\nICONST_1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayIntBefore$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayIntBefore\"\n]\nL1\nFRAME SAME1 I\nL2\nLINENUMBER 110 L2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"int\"\nICONST_2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayIntBefore$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayIntBefore\"\n]\nL3\nFRAME FULL [resources/OnMethodTest [I] [I I]\nL4\nLINENUMBER 111 L4\nL5\nLINENUMBER 112 L5\nL6\nLINENUMBER 113 L6\nL7\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L7 0\nLOCALVARIABLE a [I L2 L7 1\nLOCALVARIABLE b [[I L4 L7 2\nLOCALVARIABLE c [Ljava/lang/String; L5 L7 3\nLOCALVARIABLE d [[Ljava/lang/String; L6 L7 4\nMAXSTACK = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/NewArrayStringAfter",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nALOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayStringAfter$args(Ljava/lang/Object;[Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayStringAfter\"\n]\nFRAME FULL [resources/OnMethodTest [I [[I [Ljava/lang/String;] [[Ljava/lang/String;]\nASTORE 4\nL4\nLINENUMBER 112 L4\nASTORE 5\nL5\nLINENUMBER 113 L5\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE a [I L1 L6 1\nLOCALVARIABLE b [[I L2 L6 2\nLOCALVARIABLE c [Ljava/lang/String; L4 L6 4\nLOCALVARIABLE d [[Ljava/lang/String; L5 L6 5\nMAXSTACK = 3\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/NewArrayStringBefore",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"java.lang.String\"\nICONST_1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayStringBefore$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayStringBefore\"\n]\nL3\nFRAME FULL [resources/OnMethodTest [I [[I] [I]\nL4\nLINENUMBER 112 L4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nALOAD 0\nLDC \"java.lang.String\"\nICONST_2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayStringBefore$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayStringBefore\"\n]\nL5\nFRAME FULL [resources/OnMethodTest [I [[I [Ljava/lang/String;] [I I]\nL6\nLINENUMBER 113 L6\nL7\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L7 0\nLOCALVARIABLE a [I L1 L7 1\nLOCALVARIABLE b [[I L2 L7 2\nLOCALVARIABLE c [Ljava/lang/String; L4 L7 3\nLOCALVARIABLE d [[Ljava/lang/String; L6 L7 4\nMAXSTACK = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/NewBefore",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"java.util.HashMap\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewBefore$args(Ljava/lang/Object;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewBefore\"\n]\nL1\nFRAME SAME\nL2\nLINENUMBER 106 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE m Ljava/util/Map; L2 L3 1"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/NoArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NoArgs$argsEmpty(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NoArgs\"\n]\nFRAME SAME"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/NoArgsEntryReturn",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NoArgsEntryReturn$argsEmptyEntry(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NoArgsEntryReturn\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 6\nALOAD 0\nLLOAD 6\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NoArgsEntryReturn$argsEmptyReturn(Ljava/lang/Object;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NoArgsEntryReturn\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 5\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/NoArgsEntryReturnNoCapture",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NoArgsEntryReturnNoCapture$argsEmptyEntry(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NoArgsEntryReturnNoCapture\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NoArgsEntryReturnNoCapture$argsEmptyReturn(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NoArgsEntryReturnNoCapture\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/StaticArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nLLOAD 1\nALOAD 3\nALOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticArgs$args(Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticArgs\"\n]\nFRAME SAME\nMAXSTACK = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/StaticArgsReturn",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 5\nALOAD 0\nLLOAD 5\nLLOAD 1\nALOAD 3\nALOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticArgsReturn$args(Ljava/lang/String;JJ[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticArgsReturn\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE a Ljava/lang/String; L0 L2 0\nLOCALVARIABLE b J L0 L2 1\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 3\nLOCALVARIABLE d [I L0 L2 4\nMAXSTACK = 9\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/StaticArgsSelf",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nACONST_NULL\nALOAD 0\nLLOAD 1\nALOAD 3\nALOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticArgsSelf$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticArgsSelf\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/StaticMethodCall",
    "content": "LSTORE 4\nASTORE 6\nASTORE 7\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 6\nLLOAD 4\nALOAD 7\nLDC \"special long resources.OnMethodTest#callTarget(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevelStatic\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticMethodCall$args(Ljava/lang/String;JLjava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticMethodCall\"\n]\nL2\nFRAME FULL [java/lang/String J resources/OnMethodTest J java/lang/String resources/OnMethodTest] [J]\nALOAD 7\nALOAD 6\nLLOAD 4\nL3\nLOCALVARIABLE a Ljava/lang/String; L0 L3 0\nLOCALVARIABLE b J L0 L3 1\nLOCALVARIABLE instance Lresources/OnMethodTest; L1 L3 3\nMAXSTACK = 9\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/StaticMethodCallStatic",
    "content": "LSTORE 4\nASTORE 6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 6\nLLOAD 4\nLDC \"static long resources.OnMethodTest#callTargetStatic(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevelStatic\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticMethodCallStatic$args(Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticMethodCallStatic\"\n]\nL2\nFRAME APPEND [resources/OnMethodTest J java/lang/String]\nALOAD 6\nLLOAD 4\nL3\nLOCALVARIABLE a Ljava/lang/String; L0 L3 0\nLOCALVARIABLE b J L0 L3 1\nLOCALVARIABLE instance Lresources/OnMethodTest; L1 L3 3\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/StaticNoArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticNoArgs$argsEmpty()V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticNoArgs\"\n]\nFRAME SAME\nMAXSTACK = 1"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/StaticNoArgsSelf",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nACONST_NULL\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticNoArgsSelf$argsEmpty(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticNoArgsSelf\"\n]\nFRAME SAME\nMAXSTACK = 1"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/SyncEntry",
    "content": "TRYCATCHBLOCK L4 L5 L5 java/lang/Throwable\nDUP\nASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L6\nALOAD 0\nLDC \"sync\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncEntry$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncEntry\"\n]\nL6\nFRAME FULL [resources/OnMethodTest resources/OnMethodTest resources/OnMethodTest] [resources/OnMethodTest]\nL7\nLINENUMBER 127 L7\nGOTO L8\nFRAME FULL [resources/OnMethodTest java/lang/Object resources/OnMethodTest] [java/lang/Throwable]\nASTORE 3\nALOAD 3\nL8\nLINENUMBER 128 L8\nFRAME FULL [resources/OnMethodTest T resources/OnMethodTest] []\nL5\nFRAME FULL [resources/OnMethodTest] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L4 L5 0\nMAXSTACK = 4\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/SyncExit",
    "content": "TRYCATCHBLOCK L4 L5 L5 java/lang/Throwable\nL6\nLINENUMBER 127 L6\nDUP\nASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L7\nALOAD 0\nLDC \"resources.OnMethodTest\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncExit$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncExit\"\n]\nL7\nFRAME FULL [resources/OnMethodTest resources/OnMethodTest resources/OnMethodTest] [resources/OnMethodTest]\nGOTO L8\nASTORE 3\nDUP\nASTORE 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L9\nALOAD 0\nLDC \"resources.OnMethodTest\"\nALOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncExit$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncExit\"\n]\nL9\nFRAME FULL [resources/OnMethodTest java/lang/Object T java/lang/Throwable java/lang/Object] [java/lang/Object]\nALOAD 3\nL8\nLINENUMBER 128 L8\nFRAME FULL [resources/OnMethodTest T resources/OnMethodTest] []\nL5\nFRAME FULL [resources/OnMethodTest] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L4 L5 0\nMAXSTACK = 4\nMAXLOCALS = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/SyncMEntry",
    "content": "TRYCATCHBLOCK L4 L5 L5 java/lang/Throwable\nDUP\nASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L6\nALOAD 0\nLDC \"syncM\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncMEntry$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncMEntry\"\n]\nL6\nFRAME FULL [resources/OnMethodTest java/lang/Object java/lang/Object] [java/lang/Object]\nL7\nLINENUMBER 167 L7\nGOTO L8\nFRAME SAME1 java/lang/Throwable\nASTORE 3\nALOAD 3\nL8\nLINENUMBER 168 L8\nFRAME FULL [resources/OnMethodTest T java/lang/Object] []\nL5\nFRAME FULL [resources/OnMethodTest] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L4 L5 0\nMAXSTACK = 4\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/SyncMExit",
    "content": "TRYCATCHBLOCK L4 L5 L5 java/lang/Throwable\nL6\nLINENUMBER 167 L6\nDUP\nASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L7\nALOAD 0\nLDC \"resources.OnMethodTest\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncMExit$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncMExit\"\n]\nL7\nFRAME FULL [resources/OnMethodTest java/lang/Object java/lang/Object] [java/lang/Object]\nGOTO L8\nASTORE 3\nDUP\nASTORE 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L9\nALOAD 0\nLDC \"resources.OnMethodTest\"\nALOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncMExit$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncMExit\"\n]\nL9\nFRAME FULL [resources/OnMethodTest java/lang/Object T java/lang/Throwable java/lang/Object] [java/lang/Object]\nALOAD 3\nL8\nLINENUMBER 168 L8\nFRAME FULL [resources/OnMethodTest T java/lang/Object] []\nL5\nFRAME FULL [resources/OnMethodTest] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L4 L5 0\nMAXSTACK = 4\nMAXLOCALS = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/Throw",
    "content": "DUP\nASTORE 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"resources.OnMethodTest\"\nLDC \"exception\"\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Throw$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Throw\"\n]\nL2\nFRAME FULL [resources/OnMethodTest java/io/IOException] [java/io/IOException]\nFRAME FULL [resources/OnMethodTest] [java/io/IOException]\nASTORE 2\nL3\nLINENUMBER 85 L3\nALOAD 2\nL4\nLINENUMBER 87 L4\nL5\nLOCALVARIABLE e Ljava/io/IOException; L3 L4 2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nMAXSTACK = 5\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/AnytypeArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nICONST_4\nANEWARRAY java/lang/Object\nDUP\nICONST_0\nALOAD 1\nAASTORE\nDUP\nICONST_1\nLLOAD 2\nINVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;\nAASTORE\nDUP\nICONST_2\nALOAD 4\nAASTORE\nDUP\nICONST_3\nALOAD 5\nAASTORE\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AnytypeArgs$args(Ljava/lang/Object;[Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AnytypeArgs\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/AnytypeArgsNoSelf",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nICONST_4\nANEWARRAY java/lang/Object\nDUP\nICONST_0\nALOAD 1\nAASTORE\nDUP\nICONST_1\nLLOAD 2\nINVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;\nAASTORE\nDUP\nICONST_2\nALOAD 4\nAASTORE\nDUP\nICONST_3\nALOAD 5\nAASTORE\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$AnytypeArgsNoSelf$argsNoSelf([Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/AnytypeArgsNoSelf\"\n]\nFRAME SAME\nMAXSTACK = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/Args",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Args$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Args\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/Args2Sampled",
    "content": "ICONST_0\nISTORE 6\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hit (I)Z\nISTORE 6\nILOAD 6\nIFEQ L0\nL1\nFRAME APPEND [I]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Args2Sampled$args2(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Args2Sampled\"\n]\nFRAME SAME\nILOAD 6\nIFEQ L2\nL3\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Args2Sampled$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Args2Sampled\"\n]\nL2\nLINENUMBER 57 L2\nFRAME SAME\nL4\nLOCALVARIABLE this Lresources/OnMethodTest; L2 L4 0\nLOCALVARIABLE a Ljava/lang/String; L2 L4 1\nLOCALVARIABLE b J L2 L4 2\nLOCALVARIABLE c [Ljava/lang/String; L2 L4 4\nLOCALVARIABLE d [I L2 L4 5\nMAXSTACK = 6\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsDuration",
    "content": "LCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nDUP2\nLSTORE 10\nALOAD 0\nLLOAD 10\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration\"\n]\nL2\nFRAME SAME1 J\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L3 4\nLOCALVARIABLE d [I L0 L3 5\nMAXSTACK = 12\nMAXLOCALS = 12"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsDuration2",
    "content": "LCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nDUP2\nLSTORE 10\nALOAD 0\nLLOAD 10\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2$args2(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2\"\n]\nL2\nFRAME SAME1 J\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nDUP2\nLSTORE 12\nALOAD 0\nLLOAD 12\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2\"\n]\nL3\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J T T] [J]\nL4\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L4 0\nLOCALVARIABLE a Ljava/lang/String; L0 L4 1\nLOCALVARIABLE b J L0 L4 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L4 4\nLOCALVARIABLE d [I L0 L4 5\nMAXSTACK = 12\nMAXLOCALS = 14"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsDuration2Err",
    "content": "TRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nTRYCATCHBLOCK L0 L2 L2 java/lang/Throwable\nLCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 8\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nDUP\nASTORE 10\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLLOAD 6\nALOAD 10\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2Err$args2(Ljava/lang/Object;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2Err\"\n]\nL3\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J java/lang/Throwable] [java/lang/Throwable]\nATHROW\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nDUP\nASTORE 11\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLLOAD 6\nALOAD 11\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2Err$args(Ljava/lang/Object;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2Err\"\n]\nL4\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J T java/lang/Throwable] [java/lang/Throwable]\nATHROW\nMAXSTACK = 5\nMAXLOCALS = 12"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsDuration2Sampled",
    "content": "LCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nICONST_0\nISTORE 10\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitTimed (I)J\nDUP2\nLSTORE 8\nL2I\nISTORE 10\nILOAD 10\nIFEQ L1\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.getEndTs (I)J\nLLOAD 8\nLSUB\nLSTORE 6\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J I] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 11\nALOAD 0\nLLOAD 11\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2Sampled$args2(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2Sampled\"\n]\nL1\nFRAME SAME1 J\nILOAD 10\nIFEQ L3\nL4\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J I T T] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nDUP2\nLSTORE 13\nALOAD 0\nLLOAD 13\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDuration2Sampled$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDuration2Sampled\"\n]\nL3\nFRAME SAME1 J\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a Ljava/lang/String; L0 L5 1\nLOCALVARIABLE b J L0 L5 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L5 4\nLOCALVARIABLE d [I L0 L5 5\nMAXSTACK = 12\nMAXLOCALS = 15"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsDurationBoxed",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsDurationBoxedErr",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsDurationConstructor",
    "content": "LCONST_0\nLSTORE 2\nLCONST_0\nLSTORE 4\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 4\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 4\nLSUB\nLSTORE 2\nL3\nFRAME FULL [resources/OnMethodTest java/lang/String J J] []\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLLOAD 2\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationConstructor$args(Ljava/lang/Object;JLjava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationConstructor\"\n]\nL4\nFRAME SAME\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a Ljava/lang/String; L0 L5 1\nMAXSTACK = 4\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsDurationConstructorErr",
    "content": "TRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nL2\nLINENUMBER 41 L2\nLCONST_0\nLSTORE 1\nLCONST_0\nLSTORE 3\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 3\nL0\nLINENUMBER 42 L0\nL3\nLINENUMBER 43 L3\nL1\nFRAME FULL [resources/OnMethodTest J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 3\nLSUB\nLSTORE 1\nDUP\nASTORE 5\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLLOAD 1\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationConstructorErr$args(Ljava/lang/Object;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationConstructorErr\"\n]\nL4\nFRAME FULL [resources/OnMethodTest J J java/lang/Throwable] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L2 L1 0\nMAXSTACK = 5\nMAXLOCALS = 6\nTRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nL2\nLINENUMBER 45 L2\nLCONST_0\nLSTORE 2\nLCONST_0\nLSTORE 4\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 4\nL0\nLINENUMBER 46 L0\nL3\nLINENUMBER 47 L3\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 4\nLSUB\nLSTORE 2\nDUP\nASTORE 6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nALOAD 0\nLLOAD 2\nALOAD 6\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationConstructorErr$args(Ljava/lang/Object;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationConstructorErr\"\n]\nL4\nFRAME FULL [resources/OnMethodTest java/lang/String J J java/lang/Throwable] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L2 L1 0\nLOCALVARIABLE a Ljava/lang/String; L2 L1 1\nMAXSTACK = 5\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsDurationErr",
    "content": "TRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nLCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 8\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nDUP\nASTORE 10\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLLOAD 6\nALOAD 10\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationErr$args(Ljava/lang/Object;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationErr\"\n]\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J java/lang/Throwable] [java/lang/Throwable]\nATHROW\nMAXSTACK = 5\nMAXLOCALS = 11"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsDurationMultiReturn",
    "content": "LCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 8\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 8\nLSUB\nLSTORE 6\nL3\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L4\nDUP2\nLSTORE 10\nALOAD 0\nLLOAD 10\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationMultiReturn$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationMultiReturn\"\n]\nL4\nFRAME SAME1 J\nIFLE L5\nL6\nLINENUMBER 145 L6\nL7\nFRAME SAME1 J\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L8\nDUP2\nLSTORE 12\nALOAD 0\nLLOAD 12\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationMultiReturn$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationMultiReturn\"\n]\nL8\nFRAME SAME1 J\nL5\nLINENUMBER 149 L5\nL9\nLINENUMBER 150 L9\nL10\nFRAME SAME1 J\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L11\nDUP2\nLSTORE 14\nALOAD 0\nLLOAD 14\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationMultiReturn$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationMultiReturn\"\n]\nL11\nFRAME SAME1 J\nL12\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L12 0\nLOCALVARIABLE a Ljava/lang/String; L0 L12 1\nLOCALVARIABLE b J L0 L12 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L12 4\nLOCALVARIABLE d [I L0 L12 5\nMAXSTACK = 12\nMAXLOCALS = 16"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsDurationSampled",
    "content": "LCONST_0\nLSTORE 6\nLCONST_0\nLSTORE 8\nICONST_0\nISTORE 10\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitTimed (I)J\nDUP2\nLSTORE 8\nL2I\nISTORE 10\nILOAD 10\nIFEQ L1\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.getEndTs (I)J\nLLOAD 8\nLSUB\nLSTORE 6\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I J J I] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 11\nALOAD 0\nLLOAD 11\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsDurationSampled$args(Ljava/lang/Object;JJLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsDurationSampled\"\n]\nL1\nFRAME SAME1 J\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L3 4\nLOCALVARIABLE d [I L0 L3 5\nMAXSTACK = 12\nMAXLOCALS = 13"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsNoSelf",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nLDC \"public long resources.OnMethodTest#args(java.lang.String, long, java.lang.String[], int[])\"\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsNoSelf$argsNoSelf(Ljava/lang/String;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsNoSelf\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsReturn",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 6\nALOAD 0\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsReturn$args(Ljava/lang/Object;JLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsReturn\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 10\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsReturnAugmented",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLSTORE 6\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nLLOAD 6\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsReturnAugmented$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[IJ)J [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsReturnAugmented\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 8\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsReturnAugmented1",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLSTORE 6\nALOAD 0\nLLOAD 6\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsReturnAugmented1$args(Ljava/lang/Object;JLjava/lang/String;J[Ljava/lang/String;[I)J [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsReturnAugmented1\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 8\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsReturnSampled",
    "content": "ICONST_0\nISTORE 6\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hit (I)Z\nISTORE 6\nILOAD 6\nIFEQ L1\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J [Ljava/lang/String; [I I] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 7\nALOAD 0\nLLOAD 7\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsReturnSampled$args(Ljava/lang/Object;JLjava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsReturnSampled\"\n]\nL1\nFRAME SAME1 J\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L3 4\nLOCALVARIABLE d [I L0 L3 5\nMAXSTACK = 10\nMAXLOCALS = 9"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsSampled",
    "content": "ICONST_0\nISTORE 6\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hit (I)Z\nISTORE 6\nILOAD 6\nIFEQ L0\nL1\nFRAME APPEND [I]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsSampled$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsSampled\"\n]\nFRAME SAME\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 6\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsSampledAdaptive",
    "content": "ICONST_0\nISTORE 6\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitAdaptive (I)Z\nISTORE 6\nILOAD 6\nIFEQ L0\nL1\nFRAME APPEND [I]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsSampledAdaptive$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsSampledAdaptive\"\n]\nFRAME SAME\nILOAD 6\nIFEQ L2\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.updateEndTs (I)V\nL2\nFRAME SAME1 J\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L3 4\nLOCALVARIABLE d [I L0 L3 5\nMAXSTACK = 6\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsSampledNoSampling",
    "content": "ICONST_0\nISTORE 6\nICONST_1\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hit (I)Z\nISTORE 6\nILOAD 6\nIFEQ L0\nL1\nFRAME APPEND [I]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsSampledNoSampling$argsSampled(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsSampledNoSampling\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsSampledNoSampling$argsNoSampling(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsSampledNoSampling\"\n]\nL2\nLINENUMBER 57 L2\nFRAME SAME\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L2 L3 0\nLOCALVARIABLE a Ljava/lang/String; L2 L3 1\nLOCALVARIABLE b J L2 L3 2\nLOCALVARIABLE c [Ljava/lang/String; L2 L3 4\nLOCALVARIABLE d [I L2 L3 5\nMAXSTACK = 6\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsShared",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsShared$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsShared\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArgsUnsafe",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nALOAD 1\nLLOAD 2\nALOAD 4\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArgsUnsafe$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArgsUnsafe\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArrayGetAfter",
    "content": "DUP2\nISTORE 3\nASTORE 4\nDUP\nISTORE 5\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nILOAD 5\nALOAD 4\nILOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArrayGetAfter$args(Ljava/lang/Object;I[II)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArrayGetAfter\"\n]\nFRAME FULL [resources/OnMethodTest I [I I [I I] [I]\nISTORE 6\nL3\nLINENUMBER 97 L3\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L3 L5 6\nMAXSTACK = 5\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArrayGetAfterAny",
    "content": "DUP2\nISTORE 3\nASTORE 4\nDUP\nISTORE 5\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nILOAD 5\nINVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\nALOAD 4\nILOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArrayGetAfterAny$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArrayGetAfterAny\"\n]\nFRAME FULL [resources/OnMethodTest I [I I [I I] [I]\nISTORE 6\nL3\nLINENUMBER 97 L3\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L3 L5 6\nMAXSTACK = 5\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArrayGetBefore",
    "content": "DUP2\nASTORE 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nALOAD 4\nILOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArrayGetBefore$args(Ljava/lang/Object;[II)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArrayGetBefore\"\n]\nFRAME FULL [resources/OnMethodTest I [I I [I] [[I I]\nIALOAD\nISTORE 5\nL3\nLINENUMBER 97 L3\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L3 L5 5\nMAXSTACK = 5\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArrayGetBeforeAny",
    "content": "DUP2\nASTORE 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nALOAD 4\nILOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArrayGetBeforeAny$args(Ljava/lang/Object;Ljava/lang/Object;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArrayGetBeforeAny\"\n]\nFRAME FULL [resources/OnMethodTest I [I I [I] [[I I]\nIALOAD\nISTORE 5\nL3\nLINENUMBER 97 L3\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L3 L5 5\nMAXSTACK = 5\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArraySetAfter",
    "content": "ISTORE 4\nDUP2\nISTORE 5\nASTORE 6\nILOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nALOAD 6\nILOAD 5\nILOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArraySetAfter$args(Ljava/lang/Object;[III)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArraySetAfter\"\n]\nFRAME FULL [resources/OnMethodTest I [I I I I [I] []\nMAXSTACK = 4\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArraySetAfterAny",
    "content": "ISTORE 4\nDUP2\nISTORE 5\nASTORE 6\nILOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nALOAD 6\nILOAD 5\nILOAD 4\nINVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArraySetAfterAny$args(Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArraySetAfterAny\"\n]\nFRAME FULL [resources/OnMethodTest I [I I I I [I] []\nMAXSTACK = 4\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArraySetBefore",
    "content": "ISTORE 4\nDUP2\nISTORE 5\nASTORE 6\nILOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nALOAD 6\nILOAD 5\nILOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArraySetBefore$args(Ljava/lang/Object;[III)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArraySetBefore\"\n]\nL3\nFRAME FULL [resources/OnMethodTest I [I I I I [I] [[I I I]\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L2 L5 3\nMAXSTACK = 7\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ArraySetBeforeAny",
    "content": "ISTORE 4\nDUP2\nISTORE 5\nASTORE 6\nILOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nALOAD 6\nILOAD 5\nILOAD 4\nINVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ArraySetBeforeAny$args(Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ArraySetBeforeAny\"\n]\nL3\nFRAME FULL [resources/OnMethodTest I [I I I I [I] [[I I I]\nL4\nLINENUMBER 98 L4\nL5\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nLOCALVARIABLE a I L0 L5 1\nLOCALVARIABLE arr [I L1 L5 2\nLOCALVARIABLE b I L2 L5 3\nMAXSTACK = 7\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/Catch",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Catch$args(Ljava/lang/Object;Ljava/io/IOException;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Catch\"\n]\nFRAME FULL [resources/OnMethodTest java/io/IOException] [java/io/IOException]\nASTORE 2\nL3\nLINENUMBER 85 L3\nALOAD 2\nL4\nLINENUMBER 87 L4\nL5\nLOCALVARIABLE e Ljava/io/IOException; L3 L4 2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/CheckcastAfter",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"casts\"\nLDC \"java.util.HashMap\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$CheckcastAfter$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/CheckcastAfter\"\n]\nFRAME FULL [resources/OnMethodTest java/util/HashMap java/util/HashMap] [java/util/HashMap]\nASTORE 3\nL3\nLINENUMBER 119 L3\nIFEQ L4\nL5\nLINENUMBER 120 L5\nL4\nLINENUMBER 122 L4\nFRAME FULL [resources/OnMethodTest java/util/Map java/util/HashMap java/util/HashMap] []\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE c Ljava/util/Map; L1 L6 1\nLOCALVARIABLE d Ljava/util/HashMap; L3 L6 3\nMAXSTACK = 5\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/CheckcastBefore",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"resources.OnMethodTest\"\nLDC \"java.util.HashMap\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$CheckcastBefore$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/CheckcastBefore\"\n]\nFRAME FULL [resources/OnMethodTest java/util/HashMap java/util/HashMap] [java/util/HashMap]\nCHECKCAST java/util/HashMap\nASTORE 3\nL3\nLINENUMBER 119 L3\nIFEQ L4\nL5\nLINENUMBER 120 L5\nL4\nLINENUMBER 122 L4\nFRAME FULL [resources/OnMethodTest java/util/Map java/util/HashMap java/util/HashMap] []\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE c Ljava/util/Map; L1 L6 1\nLOCALVARIABLE d Ljava/util/HashMap; L3 L6 3\nMAXSTACK = 5\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ConstructorArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ConstructorArgs$args(Ljava/lang/Object;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ConstructorArgs\"\n]\nFRAME FULL [resources/OnMethodTest java/lang/String] []"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/Error",
    "content": "TRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nFRAME SAME1 java/lang/Throwable\nDUP\nASTORE 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"uncaught\"\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Error$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Error\"\n]\nL2\nFRAME FULL [resources/OnMethodTest java/lang/Throwable] [java/lang/Throwable]\nATHROW\nMAXSTACK = 4\nMAXLOCALS = 2"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ErrorCaught",
    "content": "TRYCATCHBLOCK L0 L2 L2 java/lang/Throwable\nL3\nLINENUMBER 180 L3\nL4\nLINENUMBER 182 L4\nL2\nFRAME SAME1 java/lang/Throwable\nDUP\nASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nALOAD 0\nLDC \"caught\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ErrorCaught$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ErrorCaught\"\n]\nL5\nFRAME FULL [resources/OnMethodTest T java/lang/Throwable] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE e Ljava/lang/RuntimeException; L3 L4 1\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nMAXSTACK = 4\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/ErrorDuration",
    "content": "TRYCATCHBLOCK L0 L1 L1 java/lang/Throwable\nLCONST_0\nLSTORE 1\nLCONST_0\nLSTORE 3\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 3\nFRAME FULL [resources/OnMethodTest J J] [java/lang/Throwable]\nINVOKESTATIC java/lang/System.nanoTime ()J\nLLOAD 3\nLSUB\nLSTORE 1\nDUP\nASTORE 5\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"uncaught\"\nLLOAD 1\nALOAD 5\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$ErrorDuration$args(Ljava/lang/Object;Ljava/lang/String;JLjava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/ErrorDuration\"\n]\nL2\nFRAME FULL [resources/OnMethodTest J J java/lang/Throwable] [java/lang/Throwable]\nATHROW\nMAXSTACK = 6\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/FieldGetAfter",
    "content": "DUP\nASTORE 1\nDUP\nISTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 1\nLDC \"field int resources.OnMethodTest#field\"\nILOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldGetAfter$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldGetAfter\"\n]\nL1\nFRAME FULL [resources/OnMethodTest resources/OnMethodTest I] [resources/OnMethodTest I]\nL2\nLINENUMBER 102 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nMAXSTACK = 6\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/FieldGetAfterStatic",
    "content": "DUP2\nLSTORE 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nACONST_NULL\nLDC \"static field long resources.OnMethodTest#sField\"\nLLOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldGetAfterStatic$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldGetAfterStatic\"\n]\nL1\nFRAME FULL [resources/OnMethodTest J] [J]\nL2\nLINENUMBER 162 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nMAXSTACK = 7\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/FieldGetBefore",
    "content": "DUP\nASTORE 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 1\nLDC \"field\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldGetBefore$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldGetBefore\"\n]\nL1\nFRAME FULL [resources/OnMethodTest resources/OnMethodTest] [resources/OnMethodTest resources/OnMethodTest]\nL2\nLINENUMBER 102 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nMAXSTACK = 5\nMAXLOCALS = 2"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/FieldGetBeforeStatic",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nACONST_NULL\nLDC \"sField\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldGetBeforeStatic$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldGetBeforeStatic\"\n]\nL1\nFRAME SAME\nL2\nLINENUMBER 162 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/FieldSetAfter",
    "content": "ISTORE 1\nDUP\nASTORE 2\nILOAD 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 2\nLDC \"field\"\nILOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldSetAfter$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldSetAfter\"\n]\nFRAME APPEND [I resources/OnMethodTest]\nMAXSTACK = 4\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/FieldSetAfterStatic",
    "content": "LSTORE 1\nLLOAD 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nACONST_NULL\nLDC \"sField\"\nLLOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldSetAfterStatic$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldSetAfterStatic\"\n]\nFRAME APPEND [J]\nMAXSTACK = 5\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/FieldSetBefore",
    "content": "ISTORE 1\nDUP\nASTORE 2\nILOAD 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 2\nLDC \"field\"\nILOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldSetBefore$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldSetBefore\"\n]\nL1\nFRAME FULL [resources/OnMethodTest I resources/OnMethodTest] [resources/OnMethodTest I]\nL2\nLINENUMBER 102 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nMAXSTACK = 6\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/FieldSetBeforeStatic",
    "content": "LSTORE 1\nLLOAD 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nACONST_NULL\nLDC \"sField\"\nLLOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$FieldSetBeforeStatic$args(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/FieldSetBeforeStatic\"\n]\nL1\nFRAME FULL [resources/OnMethodTest J] [J]\nL2\nLINENUMBER 162 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nMAXSTACK = 7\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/InstanceofAfter",
    "content": "DUP\nASTORE 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"casts\"\nLDC \"java.util.HashMap\"\nALOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$InstanceofAfter$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/InstanceofAfter\"\n]\nL3\nFRAME FULL [resources/OnMethodTest java/util/HashMap java/util/HashMap java/util/HashMap] [I]\nIFEQ L4\nL5\nLINENUMBER 120 L5\nL4\nLINENUMBER 122 L4\nFRAME FULL [resources/OnMethodTest java/util/Map java/util/HashMap java/util/HashMap] []\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE c Ljava/util/Map; L1 L6 1\nLOCALVARIABLE d Ljava/util/HashMap; L2 L6 2\nMAXSTACK = 5\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/InstanceofBefore",
    "content": "DUP\nASTORE 3\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"resources.OnMethodTest\"\nLDC \"java.util.HashMap\"\nALOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$InstanceofBefore$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/InstanceofBefore\"\n]\nL3\nFRAME FULL [resources/OnMethodTest java/util/HashMap java/util/HashMap java/util/HashMap] [java/util/HashMap]\nIFEQ L4\nL5\nLINENUMBER 120 L5\nL4\nLINENUMBER 122 L4\nFRAME FULL [resources/OnMethodTest java/util/Map java/util/HashMap java/util/HashMap] []\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE c Ljava/util/Map; L1 L6 1\nLOCALVARIABLE d Ljava/util/HashMap; L2 L6 2\nMAXSTACK = 5\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/Line",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"exception\"\nLDC 84\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Line$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Line\"\n]\nL2\nFRAME SAME1 java/lang/Throwable\nL3\nLINENUMBER 85 L3\nL4\nLINENUMBER 87 L4\nL5\nLOCALVARIABLE e Ljava/io/IOException; L3 L4 1\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nMAXSTACK = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MatchDerived",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCall",
    "content": "LSTORE 4\nASTORE 6\nASTORE 7\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 6\nLLOAD 4\nALOAD 7\nLDC \"special long resources.OnMethodTest#callTarget(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevel\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCall$args(Ljava/lang/Object;Ljava/lang/String;JLjava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCall\"\n]\nL1\nFRAME APPEND [J java/lang/String resources/OnMethodTest]\nALOAD 7\nALOAD 6\nLLOAD 4\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 8\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCallDuration",
    "content": "LCONST_0\nLSTORE 4\nLCONST_0\nLSTORE 6\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 6\nLSTORE 8\nASTORE 10\nASTORE 11\nALOAD 11\nALOAD 10\nLLOAD 8\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 12\nLLOAD 12\nLCONST_0\nALOAD 10\nLLOAD 8\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDuration$args(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDuration\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J J J java/lang/String resources/OnMethodTest] [J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 9\nMAXLOCALS = 14"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCallDuration2",
    "content": "LCONST_0\nLSTORE 4\nLCONST_0\nLSTORE 6\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 6\nLSTORE 8\nASTORE 10\nASTORE 11\nALOAD 11\nALOAD 10\nLLOAD 8\nLCONST_0\nLSTORE 12\nLCONST_0\nLSTORE 14\nINVOKESTATIC java/lang/System.nanoTime ()J\nLSTORE 14\nLSTORE 16\nASTORE 18\nASTORE 19\nALOAD 19\nALOAD 18\nLLOAD 16\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 20\nLLOAD 20\nLCONST_0\nALOAD 18\nLLOAD 16\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDuration2$args0(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDuration2\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J J J java/lang/String resources/OnMethodTest J J J java/lang/String resources/OnMethodTest] [J]\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nDUP2\nLSTORE 22\nLLOAD 22\nLCONST_0\nALOAD 10\nLLOAD 8\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDuration2$args1(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDuration2\"\n]\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J J J J java/lang/String resources/OnMethodTest J J J java/lang/String resources/OnMethodTest T T] [J]\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nMAXSTACK = 9\nMAXLOCALS = 24"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCallDurationSampled",
    "content": "LCONST_0\nLSTORE 4\nLCONST_0\nLSTORE 6\nICONST_0\nISTORE 8\nICONST_2\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitTimed (I)J\nDUP2\nLSTORE 6\nL2I\nISTORE 8\nLSTORE 9\nASTORE 11\nASTORE 12\nALOAD 12\nALOAD 11\nLLOAD 9\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 13\nLLOAD 13\nLCONST_0\nALOAD 11\nLLOAD 9\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDurationSampled$args(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDurationSampled\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J J I J java/lang/String resources/OnMethodTest] [J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 9\nMAXLOCALS = 15"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCallDurationSampledMulti",
    "content": "LCONST_0\nLSTORE 4\nLCONST_0\nLSTORE 6\nICONST_0\nISTORE 8\nICONST_2\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitTimed (I)J\nDUP2\nLSTORE 6\nL2I\nISTORE 8\nLSTORE 9\nASTORE 11\nASTORE 12\nALOAD 12\nALOAD 11\nLLOAD 9\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 13\nLLOAD 13\nLCONST_0\nALOAD 11\nLLOAD 9\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDurationSampledMulti$args(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDurationSampledMulti\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J J I J java/lang/String resources/OnMethodTest] [J]\nLCONST_0\nLSTORE 15\nLCONST_0\nLSTORE 17\nICONST_0\nISTORE 19\nICONST_3\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitTimed (I)J\nDUP2\nLSTORE 17\nL2I\nISTORE 19\nLSTORE 20\nASTORE 22\nALOAD 22\nLLOAD 20\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nDUP2\nLSTORE 23\nLLOAD 23\nLCONST_0\nALOAD 22\nLLOAD 20\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallDurationSampledMulti$args(JJLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallDurationSampledMulti\"\n]\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J J J I J java/lang/String resources/OnMethodTest T T J J I J java/lang/String] [J J]\nLSTORE 25\nL3\nLINENUMBER 132 L3\nLLOAD 25\nL4\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L4 0\nLOCALVARIABLE a Ljava/lang/String; L0 L4 1\nLOCALVARIABLE b J L0 L4 2\nLOCALVARIABLE i J L3 L4 25\nMAXSTACK = 11\nMAXLOCALS = 27"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCallNoArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallNoArgs$args()V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallNoArgs\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J] [resources/OnMethodTest java/lang/String J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCallReturn",
    "content": "LSTORE 4\nASTORE 6\nASTORE 7\nALOAD 7\nALOAD 6\nLLOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 8\nLLOAD 8\nALOAD 6\nLLOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallReturn$args(JLjava/lang/String;J)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallReturn\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J java/lang/String resources/OnMethodTest] [J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 7\nMAXLOCALS = 10"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCallReturnAugmented",
    "content": "LSTORE 4\nASTORE 6\nASTORE 7\nALOAD 7\nALOAD 6\nLLOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLSTORE 8\nALOAD 6\nLLOAD 4\nLLOAD 8\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallReturnAugmented$args(Ljava/lang/String;JJ)J [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallReturnAugmented\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J java/lang/String resources/OnMethodTest] [J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXLOCALS = 10"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCallReturnAugmented1",
    "content": "LSTORE 4\nASTORE 6\nASTORE 7\nALOAD 7\nALOAD 6\nLLOAD 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nLSTORE 8\nLLOAD 8\nALOAD 6\nLLOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallReturnAugmented1$args(JLjava/lang/String;J)J [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallReturnAugmented1\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J java/lang/String resources/OnMethodTest] [J]\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXLOCALS = 10"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCallSampled",
    "content": "ICONST_0\nISTORE 4\nICONST_2\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hit (I)Z\nISTORE 4\nLSTORE 5\nASTORE 7\nASTORE 8\nILOAD 4\nIFEQ L1\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J I J java/lang/String resources/OnMethodTest] []\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 7\nLLOAD 5\nALOAD 8\nLDC \"special long resources.OnMethodTest#callTarget(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevel\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallSampled$args(Ljava/lang/Object;Ljava/lang/String;JLjava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallSampled\"\n]\nL1\nFRAME SAME\nALOAD 8\nALOAD 7\nLLOAD 5\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nMAXSTACK = 8\nMAXLOCALS = 9"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCallSampledAdaptive",
    "content": "ICONST_0\nISTORE 4\nICONST_2\nINVOKESTATIC org/openjdk/btrace/instr/MethodTracker.hitAdaptive (I)Z\nISTORE 4\nLSTORE 5\nASTORE 7\nASTORE 8\nILOAD 4\nIFEQ L1\nL2\nFRAME FULL [resources/OnMethodTest java/lang/String J I J java/lang/String resources/OnMethodTest] []\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 7\nLLOAD 5\nALOAD 8\nLDC \"special long resources.OnMethodTest#callTarget(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevel\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallSampledAdaptive$args(Ljava/lang/Object;Ljava/lang/String;JLjava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallSampledAdaptive\"\n]\nL1\nFRAME SAME\nALOAD 8\nALOAD 7\nLLOAD 5\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE a Ljava/lang/String; L0 L3 1\nLOCALVARIABLE b J L0 L3 2\nMAXSTACK = 8\nMAXLOCALS = 9"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/MethodCallStatic",
    "content": "LSTORE 4\nASTORE 6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 6\nLLOAD 4\nLDC \"static long resources.OnMethodTest#callTargetStatic(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevel\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$MethodCallStatic$args(Ljava/lang/Object;Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/MethodCallStatic\"\n]\nL1\nFRAME FULL [resources/OnMethodTest java/lang/String J J java/lang/String] [J]\nALOAD 6\nLLOAD 4\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nMAXSTACK = 9\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/NativeWithReturn",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/NativeWithoutReturn",
    "content": ""
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/NewAfter",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 1\nLDC \"java.util.HashMap\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewAfter$args(Ljava/lang/Object;Ljava/util/Map;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewAfter\"\n]\nFRAME FULL [resources/OnMethodTest java/util/HashMap] [java/util/HashMap]\nASTORE 2\nL2\nLINENUMBER 106 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE m Ljava/util/Map; L2 L3 2\nMAXSTACK = 4\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/NewArrayIntAfter",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayIntAfter$args(Ljava/lang/Object;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayIntAfter\"\n]\nFRAME FULL [resources/OnMethodTest [I] [[I]\nASTORE 2\nL2\nLINENUMBER 110 L2\nASTORE 3\nL3\nLINENUMBER 111 L3\nASTORE 4\nL4\nLINENUMBER 112 L4\nASTORE 5\nL5\nLINENUMBER 113 L5\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE a [I L2 L6 2\nLOCALVARIABLE b [[I L3 L6 3\nLOCALVARIABLE c [Ljava/lang/String; L4 L6 4\nLOCALVARIABLE d [[Ljava/lang/String; L5 L6 5\nMAXSTACK = 3\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/NewArrayIntBefore",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"int\"\nICONST_1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayIntBefore$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayIntBefore\"\n]\nL1\nFRAME SAME1 I\nL2\nLINENUMBER 110 L2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"int\"\nICONST_2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayIntBefore$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayIntBefore\"\n]\nL3\nFRAME FULL [resources/OnMethodTest [I] [I I]\nL4\nLINENUMBER 111 L4\nL5\nLINENUMBER 112 L5\nL6\nLINENUMBER 113 L6\nL7\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L7 0\nLOCALVARIABLE a [I L2 L7 1\nLOCALVARIABLE b [[I L4 L7 2\nLOCALVARIABLE c [Ljava/lang/String; L5 L7 3\nLOCALVARIABLE d [[Ljava/lang/String; L6 L7 4\nMAXSTACK = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/NewArrayStringAfter",
    "content": "DUP\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nALOAD 3\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayStringAfter$args(Ljava/lang/Object;[Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayStringAfter\"\n]\nFRAME FULL [resources/OnMethodTest [I [[I [Ljava/lang/String;] [[Ljava/lang/String;]\nASTORE 4\nL4\nLINENUMBER 112 L4\nASTORE 5\nL5\nLINENUMBER 113 L5\nL6\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L6 0\nLOCALVARIABLE a [I L1 L6 1\nLOCALVARIABLE b [[I L2 L6 2\nLOCALVARIABLE c [Ljava/lang/String; L4 L6 4\nLOCALVARIABLE d [[Ljava/lang/String; L5 L6 5\nMAXSTACK = 3\nMAXLOCALS = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/NewArrayStringBefore",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L3\nALOAD 0\nLDC \"java.lang.String\"\nICONST_1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayStringBefore$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayStringBefore\"\n]\nL3\nFRAME FULL [resources/OnMethodTest [I [[I] [I]\nL4\nLINENUMBER 112 L4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L5\nALOAD 0\nLDC \"java.lang.String\"\nICONST_2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewArrayStringBefore$args(Ljava/lang/Object;Ljava/lang/String;I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewArrayStringBefore\"\n]\nL5\nFRAME FULL [resources/OnMethodTest [I [[I [Ljava/lang/String;] [I I]\nL6\nLINENUMBER 113 L6\nL7\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L7 0\nLOCALVARIABLE a [I L1 L7 1\nLOCALVARIABLE b [[I L2 L7 2\nLOCALVARIABLE c [Ljava/lang/String; L4 L7 3\nLOCALVARIABLE d [[Ljava/lang/String; L6 L7 4\nMAXSTACK = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/NewBefore",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nLDC \"java.util.HashMap\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NewBefore$args(Ljava/lang/Object;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NewBefore\"\n]\nL1\nFRAME SAME\nL2\nLINENUMBER 106 L2\nL3\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L3 0\nLOCALVARIABLE m Ljava/util/Map; L2 L3 1"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/NoArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NoArgs$argsEmpty(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NoArgs\"\n]\nFRAME SAME"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/NoArgsEntryReturn",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NoArgsEntryReturn$argsEmptyEntry(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NoArgsEntryReturn\"\n]\nFRAME SAME\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nALOAD 0\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$NoArgsEntryReturn$argsEmptyReturn(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/NoArgsEntryReturn\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L2 0\nLOCALVARIABLE a Ljava/lang/String; L0 L2 1\nLOCALVARIABLE b J L0 L2 2\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 4\nLOCALVARIABLE d [I L0 L2 5\nMAXSTACK = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/StaticArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nALOAD 0\nLLOAD 1\nALOAD 3\nALOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticArgs$args(Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticArgs\"\n]\nFRAME SAME\nMAXSTACK = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/StaticArgsReturn",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L1\nDUP2\nLSTORE 5\nALOAD 0\nLLOAD 5\nLLOAD 1\nALOAD 3\nALOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticArgsReturn$args(Ljava/lang/String;JJ[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticArgsReturn\"\n]\nL1\nFRAME SAME1 J\nL2\nLOCALVARIABLE a Ljava/lang/String; L0 L2 0\nLOCALVARIABLE b J L0 L2 1\nLOCALVARIABLE c [Ljava/lang/String; L0 L2 3\nLOCALVARIABLE d [I L0 L2 4\nMAXSTACK = 9\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/StaticArgsSelf",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nACONST_NULL\nALOAD 0\nLLOAD 1\nALOAD 3\nALOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticArgsSelf$args(Ljava/lang/Object;Ljava/lang/String;J[Ljava/lang/String;[I)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticArgsSelf\"\n]\nFRAME SAME\nMAXSTACK = 6"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/StaticMethodCall",
    "content": "LSTORE 4\nASTORE 6\nASTORE 7\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 6\nLLOAD 4\nALOAD 7\nLDC \"special long resources.OnMethodTest#callTarget(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevelStatic\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticMethodCall$args(Ljava/lang/String;JLjava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticMethodCall\"\n]\nL2\nFRAME FULL [java/lang/String J resources/OnMethodTest J java/lang/String resources/OnMethodTest] [J]\nALOAD 7\nALOAD 6\nLLOAD 4\nL3\nLOCALVARIABLE a Ljava/lang/String; L0 L3 0\nLOCALVARIABLE b J L0 L3 1\nLOCALVARIABLE instance Lresources/OnMethodTest; L1 L3 3\nMAXSTACK = 9\nMAXLOCALS = 8"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/StaticMethodCallStatic",
    "content": "LSTORE 4\nASTORE 6\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 6\nLLOAD 4\nLDC \"static long resources.OnMethodTest#callTargetStatic(java.lang.String, long)\"\nLDC \"resources.OnMethodTest\"\nLDC \"callTopLevelStatic\"\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticMethodCallStatic$args(Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticMethodCallStatic\"\n]\nL2\nFRAME APPEND [resources/OnMethodTest J java/lang/String]\nALOAD 6\nLLOAD 4\nL3\nLOCALVARIABLE a Ljava/lang/String; L0 L3 0\nLOCALVARIABLE b J L0 L3 1\nLOCALVARIABLE instance Lresources/OnMethodTest; L1 L3 3\nMAXLOCALS = 7"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/StaticNoArgs",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticNoArgs$argsEmpty()V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticNoArgs\"\n]\nFRAME SAME\nMAXSTACK = 1"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/StaticNoArgsSelf",
    "content": "INVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L0\nACONST_NULL\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$StaticNoArgsSelf$argsEmpty(Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/StaticNoArgsSelf\"\n]\nFRAME SAME\nMAXSTACK = 1"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/SyncEntry",
    "content": "TRYCATCHBLOCK L4 L5 L5 java/lang/Throwable\nDUP\nASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L6\nALOAD 0\nLDC \"sync\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncEntry$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncEntry\"\n]\nL6\nFRAME FULL [resources/OnMethodTest resources/OnMethodTest resources/OnMethodTest] [resources/OnMethodTest]\nL7\nLINENUMBER 127 L7\nGOTO L8\nFRAME FULL [resources/OnMethodTest java/lang/Object resources/OnMethodTest] [java/lang/Throwable]\nASTORE 3\nALOAD 3\nL8\nLINENUMBER 128 L8\nFRAME FULL [resources/OnMethodTest T resources/OnMethodTest] []\nL5\nFRAME FULL [resources/OnMethodTest] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L4 L5 0\nMAXSTACK = 4\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/SyncExit",
    "content": "TRYCATCHBLOCK L4 L5 L5 java/lang/Throwable\nL6\nLINENUMBER 127 L6\nDUP\nASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L7\nALOAD 0\nLDC \"resources.OnMethodTest\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncExit$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncExit\"\n]\nL7\nFRAME FULL [resources/OnMethodTest resources/OnMethodTest resources/OnMethodTest] [resources/OnMethodTest]\nGOTO L8\nASTORE 3\nDUP\nASTORE 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L9\nALOAD 0\nLDC \"resources.OnMethodTest\"\nALOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncExit$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncExit\"\n]\nL9\nFRAME FULL [resources/OnMethodTest java/lang/Object T java/lang/Throwable java/lang/Object] [java/lang/Object]\nALOAD 3\nL8\nLINENUMBER 128 L8\nFRAME FULL [resources/OnMethodTest T resources/OnMethodTest] []\nL5\nFRAME FULL [resources/OnMethodTest] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L4 L5 0\nMAXSTACK = 4\nMAXLOCALS = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/SyncMEntry",
    "content": "TRYCATCHBLOCK L4 L5 L5 java/lang/Throwable\nDUP\nASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L6\nALOAD 0\nLDC \"syncM\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncMEntry$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncMEntry\"\n]\nL6\nFRAME FULL [resources/OnMethodTest java/lang/Object java/lang/Object] [java/lang/Object]\nL7\nLINENUMBER 167 L7\nGOTO L8\nFRAME SAME1 java/lang/Throwable\nASTORE 3\nALOAD 3\nL8\nLINENUMBER 168 L8\nFRAME FULL [resources/OnMethodTest T java/lang/Object] []\nL5\nFRAME FULL [resources/OnMethodTest] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L4 L5 0\nMAXSTACK = 4\nMAXLOCALS = 4"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/SyncMExit",
    "content": "TRYCATCHBLOCK L4 L5 L5 java/lang/Throwable\nL6\nLINENUMBER 167 L6\nDUP\nASTORE 2\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L7\nALOAD 0\nLDC \"resources.OnMethodTest\"\nALOAD 2\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncMExit$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncMExit\"\n]\nL7\nFRAME FULL [resources/OnMethodTest java/lang/Object java/lang/Object] [java/lang/Object]\nGOTO L8\nASTORE 3\nDUP\nASTORE 4\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L9\nALOAD 0\nLDC \"resources.OnMethodTest\"\nALOAD 4\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$SyncMExit$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/SyncMExit\"\n]\nL9\nFRAME FULL [resources/OnMethodTest java/lang/Object T java/lang/Throwable java/lang/Object] [java/lang/Object]\nALOAD 3\nL8\nLINENUMBER 168 L8\nFRAME FULL [resources/OnMethodTest T java/lang/Object] []\nL5\nFRAME FULL [resources/OnMethodTest] [java/lang/Throwable]\nATHROW\nLOCALVARIABLE this Lresources/OnMethodTest; L4 L5 0\nMAXSTACK = 4\nMAXLOCALS = 5"
  },
  {
    "path": "btrace-instr/src/test/resources/instrumentorTestData/dynamic/onmethod/leveled/Throw",
    "content": "DUP\nASTORE 1\nINVOKESTATIC org/openjdk/btrace/runtime/LinkingFlag.get ()I\nIFNE L2\nALOAD 0\nLDC \"resources.OnMethodTest\"\nLDC \"exception\"\nALOAD 1\nINVOKEDYNAMIC $btrace$org$openjdk$btrace$runtime$auxiliary$Throw$args(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V [\n// handle kind 0x6 : INVOKESTATIC\norg/openjdk/btrace/runtime/IndyDispatcher.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;\n// arguments:\n\"org/openjdk/btrace/runtime/auxiliary/Throw\"\n]\nL2\nFRAME FULL [resources/OnMethodTest java/io/IOException] [java/io/IOException]\nFRAME FULL [resources/OnMethodTest] [java/io/IOException]\nASTORE 2\nL3\nLINENUMBER 85 L3\nALOAD 2\nL4\nLINENUMBER 87 L4\nL5\nLOCALVARIABLE e Ljava/io/IOException; L3 L4 2\nLOCALVARIABLE this Lresources/OnMethodTest; L0 L5 0\nMAXSTACK = 5\nMAXLOCALS = 3"
  },
  {
    "path": "btrace-instr/src/test/resources/plain.txt",
    "content": "This is a text file"
  },
  {
    "path": "btrace-runtime/build.gradle",
    "content": "sourceSets {\n\n    java9 {\n        java {\n            srcDirs = ['src/main/java9']\n        }\n    }\n    java11 {\n        java {\n            srcDirs = ['src/main/java11']\n        }\n    }\n}\n\ncompileJava {\n    sourceCompatibility = 8\n    targetCompatibility = 8\n    options.fork = true\n    javaCompiler = javaToolchains.compilerFor {\n        languageVersion.set(JavaLanguageVersion.of(8))\n    }\n}\n\ncompileJava9Java {\n    sourceCompatibility = 9\n    targetCompatibility = 9\n    options.fork = true\n    javaCompiler = javaToolchains.compilerFor {\n        languageVersion.set(JavaLanguageVersion.of(11))\n    }\n    options.compilerArgs.addAll(['--add-exports', 'java.base/jdk.internal.reflect=ALL-UNNAMED', '--add-exports', 'java.base/jdk.internal.perf=ALL-UNNAMED'])\n}\n\ncompileJava11Java {\n    sourceCompatibility = 11\n    targetCompatibility = 11\n    javaCompiler = javaToolchains.compilerFor {\n        languageVersion.set(JavaLanguageVersion.of(11))\n    }\n    options.compilerArgs.addAll(['--add-exports', 'java.base/jdk.internal.reflect=ALL-UNNAMED', '--add-exports', 'java.base/jdk.internal.perf=ALL-UNNAMED'])\n}\n\ndependencies {\n    java9Implementation files(sourceSets.main.output.classesDirs) {\n        builtBy compileJava\n    }\n    java11Implementation files(sourceSets.main.output.classesDirs) {\n        builtBy compileJava\n    }\n\n    // https://mvnrepository.com/artifact/org.slf4j/slf4j-api\n    implementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.36'\n\n    // https://mvnrepository.com/artifact/org.jctools/jctools-core\n    implementation(group: 'org.jctools', name: 'jctools-core', version: '4.0.6')\n\n    java9Implementation project(':btrace-core')\n    java9Implementation project(':btrace-extension')\n\n    java11Implementation project(':btrace-core')\n    java11Implementation project(':btrace-extension')\n\n    implementation project(':btrace-core')\n    implementation project(':btrace-extension')\n\n    testImplementation project(':btrace-extension')\n}\n\njar {\n    into('') {\n        from sourceSets.java9.output\n    }\n    into('') {\n        from sourceSets.java11.output\n    }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/BTraceMBean.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.runtime;\n\n/*\n This class is a simple implementation of DynamicMBean that exposes a BTrace class as a MBean. The\n static fields annotated with @Property are exposed as MBean attributes.\n\n @author A. Sundararajan\n*/\nimport java.lang.management.ManagementFactory;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicLong;\nimport javax.management.Attribute;\nimport javax.management.AttributeList;\nimport javax.management.AttributeNotFoundException;\nimport javax.management.Descriptor;\nimport javax.management.DynamicMBean;\nimport javax.management.InvalidAttributeValueException;\nimport javax.management.MBeanAttributeInfo;\nimport javax.management.MBeanException;\nimport javax.management.MBeanInfo;\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\nimport javax.management.ReflectionException;\nimport javax.management.modelmbean.DescriptorSupport;\nimport javax.management.openmbean.ArrayType;\nimport javax.management.openmbean.CompositeData;\nimport javax.management.openmbean.CompositeDataSupport;\nimport javax.management.openmbean.CompositeType;\nimport javax.management.openmbean.OpenDataException;\nimport javax.management.openmbean.OpenType;\nimport javax.management.openmbean.SimpleType;\nimport org.openjdk.btrace.core.Profiler;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Property;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This is a simple DynamicMBean implementation that exposes the static fields of BTrace class as\n * attributes. The fields exposed should be annotated as {@linkplain Property}.\n *\n * @author A. Sundararajan\n */\npublic class BTraceMBean implements DynamicMBean {\n  private static final Logger log = LoggerFactory.getLogger(BTraceMBean.class);\n\n  private final Class<?> clazz;\n  private final Map<String, Field> attributes;\n  private final String beanName;\n  private MBeanInfo cachedBeanInfo;\n\n  public BTraceMBean(Class<?> clazz) {\n    this.clazz = clazz;\n    attributes = getJMXAttributes(clazz);\n    beanName = getBeanName(clazz);\n  }\n\n  public static void registerMBean(Class<?> clazz) {\n    if (isMBean(clazz)) {\n      MBeanServer server = ManagementFactory.getPlatformMBeanServer();\n      BTraceMBean bean = new BTraceMBean(clazz);\n      try {\n        ObjectName on = new ObjectName(\"btrace:name=\" + bean.beanName);\n        if (server.isRegistered(on)) {\n          server.unregisterMBean(on);\n        }\n        server.registerMBean(bean, on);\n      } catch (RuntimeException re) {\n        throw re;\n      } catch (Exception exp) {\n        throw new RuntimeException(exp);\n      }\n    }\n  }\n\n  // internals only below this point\n  private static String getBeanName(Class<?> clazz) {\n    BTrace info = clazz.getAnnotation(BTrace.class);\n    String beanName = info.name();\n    if (beanName.isEmpty()) {\n      beanName = clazz.getName();\n    }\n    return beanName;\n  }\n\n  public static boolean isMBean(Class<?> clazz) {\n    // if at least one field is annotated as @Property, we create MBean\n    for (Field field : clazz.getDeclaredFields()) {\n      if (field.isAnnotationPresent(Property.class)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private static Object getFieldValue(Field field) {\n    try {\n      Object value = field.get(null);\n      OpenType<?> ot = OpenTypeUtils.typeToOpenType(field.getGenericType());\n      if (ot != null) {\n        return OpenTypeUtils.convertToOpenTypeValue(ot, value);\n      } else {\n        // no conversion attempted!\n        return value;\n      }\n    } catch (RuntimeException re) {\n      throw re;\n    } catch (Exception exp) {\n      throw new RuntimeException(exp);\n    }\n  }\n\n  private static Map<String, Field> getJMXAttributes(Class<?> clazz) {\n    try {\n      Map<String, Field> fields = new HashMap<>();\n      for (Field field : clazz.getDeclaredFields()) {\n        if (Modifier.isStatic(field.getModifiers()) && field.isAnnotationPresent(Property.class)) {\n          Property attr = field.getAnnotation(Property.class);\n          if (attr != null) {\n            field.setAccessible(true);\n            String attrName = attr.name();\n            if (attrName.isEmpty()) {\n              attrName = field.getName();\n              // remove BTRACE_FIELD_PREFIX (\"$\") from field name\n              if (attrName.startsWith(\"$\")) {\n                attrName = attrName.substring(1);\n              }\n            }\n            fields.put(attrName, field);\n          }\n        }\n      }\n      return fields;\n    } catch (RuntimeException re) {\n      throw re;\n    } catch (Exception exp) {\n      throw new RuntimeException(exp);\n    }\n  }\n\n  @Override\n  public synchronized Object getAttribute(String name) throws AttributeNotFoundException {\n    Field field = attributes.get(name);\n    if (field == null) {\n      throw new AttributeNotFoundException(\"No such property: \" + name);\n    }\n    return getFieldValue(field);\n  }\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  public synchronized void setAttribute(Attribute attribute)\n      throws InvalidAttributeValueException, MBeanException, AttributeNotFoundException {\n    throw new MBeanException(new RuntimeException(\"BTrace attributes are read-only\"));\n  }\n\n  @Override\n  public synchronized AttributeList getAttributes(String[] names) {\n    AttributeList list = new AttributeList();\n    for (String name : names) {\n      Field field = attributes.get(name);\n      Object value = null;\n      if (field != null) {\n        value = getFieldValue(field);\n      }\n      if (value != null) {\n        list.add(new Attribute(name, value));\n      }\n    }\n    return list;\n  }\n\n  @Override\n  public synchronized AttributeList setAttributes(AttributeList list) {\n    // we don't support attribute sets -- return an empty list.\n    return new AttributeList();\n  }\n\n  @SuppressWarnings(\"RedundantThrows\")\n  @Override\n  public Object invoke(String name, Object[] args, String[] sig)\n      throws MBeanException, ReflectionException {\n    throw new ReflectionException(new NoSuchMethodException(name));\n  }\n\n  @Override\n  public synchronized MBeanInfo getMBeanInfo() {\n    if (cachedBeanInfo != null) {\n      return cachedBeanInfo;\n    }\n    SortedSet<String> names = new TreeSet<>(attributes.keySet());\n    MBeanAttributeInfo[] attrs = new MBeanAttributeInfo[names.size()];\n    Iterator<String> it = names.iterator();\n    for (int i = 0; i < attrs.length; i++) {\n      String name = it.next();\n      Field field = attributes.get(name);\n      Property attr = field.getAnnotation(Property.class);\n      String description = attr.description();\n      if (description.isEmpty()) {\n        description = name;\n      }\n      Descriptor descriptor = new DescriptorSupport();\n      OpenType<?> ot = OpenTypeUtils.typeToOpenType(field.getGenericType());\n      if (ot != null) {\n        descriptor.setField(\"openType\", ot);\n      }\n\n      attrs[i] =\n          new MBeanAttributeInfo(\n              name,\n              field.getType().getName(),\n              description,\n              true, // isReadable\n              false, // isWritable\n              false, // isIs\n              descriptor);\n    }\n\n    BTrace info = clazz.getAnnotation(BTrace.class);\n    String description = info.description();\n    if (description.isEmpty()) {\n      description = \"BTrace MBean : \" + beanName;\n    }\n    cachedBeanInfo =\n        new MBeanInfo(\n            beanName,\n            description,\n            attrs,\n            null, // constructors\n            null,\n            null); // notifications\n    return cachedBeanInfo;\n  }\n\n  private static class OpenTypeUtils {\n\n    private static final Map<Class<?>, OpenType<?>> classToOpenTypes = new HashMap<>();\n\n    static {\n      classToOpenTypes.put(Byte.TYPE, SimpleType.BYTE);\n      classToOpenTypes.put(Byte.class, SimpleType.BYTE);\n      classToOpenTypes.put(Short.TYPE, SimpleType.SHORT);\n      classToOpenTypes.put(Short.class, SimpleType.SHORT);\n      classToOpenTypes.put(Integer.TYPE, SimpleType.INTEGER);\n      classToOpenTypes.put(Integer.class, SimpleType.INTEGER);\n      classToOpenTypes.put(Long.TYPE, SimpleType.LONG);\n      classToOpenTypes.put(Long.class, SimpleType.LONG);\n      classToOpenTypes.put(Float.TYPE, SimpleType.FLOAT);\n      classToOpenTypes.put(Float.class, SimpleType.FLOAT);\n      classToOpenTypes.put(Double.TYPE, SimpleType.DOUBLE);\n      classToOpenTypes.put(Double.class, SimpleType.DOUBLE);\n      classToOpenTypes.put(Boolean.TYPE, SimpleType.BOOLEAN);\n      classToOpenTypes.put(Boolean.class, SimpleType.BOOLEAN);\n      classToOpenTypes.put(Character.TYPE, SimpleType.CHARACTER);\n      classToOpenTypes.put(Character.class, SimpleType.CHARACTER);\n      classToOpenTypes.put(AtomicInteger.class, SimpleType.INTEGER);\n      classToOpenTypes.put(AtomicLong.class, SimpleType.LONG);\n      classToOpenTypes.put(BigInteger.class, SimpleType.BIGINTEGER);\n      classToOpenTypes.put(BigDecimal.class, SimpleType.BIGDECIMAL);\n      classToOpenTypes.put(String.class, SimpleType.STRING);\n      classToOpenTypes.put(ObjectName.class, SimpleType.OBJECTNAME);\n      classToOpenTypes.put(Date.class, SimpleType.DATE);\n    }\n\n    private static OpenType<?> typeToOpenType(Type t) {\n      try {\n        // FIXME: This is highly incomplete, revisit...\n        // just enough to get Maps for now.\n        if (t instanceof Class) {\n          Class<?> c = (Class<?>) t;\n          if (Profiler.class.isAssignableFrom(c)) {\n            CompositeType record =\n                new CompositeType(\n                    \"Record\",\n                    \"Profiler record\",\n                    new String[] {\n                      \"block\",\n                      \"invocations\",\n                      \"selfTime.total\",\n                      \"selfTime.percent\",\n                      \"selfTime.avg\",\n                      \"selfTime.max\",\n                      \"selfTime.min\",\n                      \"wallTime.total\",\n                      \"wallTime.percent\",\n                      \"wallTime.avg\",\n                      \"wallTime.max\",\n                      \"wallTime.min\"\n                    },\n                    new String[] {\n                      \"block\",\n                      \"invocations\",\n                      \"selfTime.total\",\n                      \"selfTime.percent\",\n                      \"selfTime.avg\",\n                      \"selfTime.max\",\n                      \"selfTime.min\",\n                      \"wallTime.total\",\n                      \"wallTime.percent\",\n                      \"wallTime.avg\",\n                      \"wallTime.max\",\n                      \"wallTime.min\"\n                    },\n                    new OpenType[] {\n                      typeToOpenType(String.class),\n                      typeToOpenType(Long.class),\n                      typeToOpenType(Long.class),\n                      typeToOpenType(Double.class),\n                      typeToOpenType(Long.class),\n                      typeToOpenType(Long.class),\n                      typeToOpenType(Long.class),\n                      typeToOpenType(Long.class),\n                      typeToOpenType(Double.class),\n                      typeToOpenType(Long.class),\n                      typeToOpenType(Long.class),\n                      typeToOpenType(Long.class)\n                    });\n            CompositeType recordEntry =\n                new CompositeType(\n                    \"Record Entry\",\n                    \"Record map entry\",\n                    new String[] {\"key\", \"value\"},\n                    new String[] {\"key\", \"value\"},\n                    new OpenType[] {typeToOpenType(String.class), record});\n            return new CompositeType(\n                \"Snapshot\",\n                \"Profiler snapshot\",\n                new String[] {\"startTime\", \"lastRefresh\", \"interval\", \"data\"},\n                new String[] {\"startTime\", \"lastRefresh\", \"interval\", \"data\"},\n                new OpenType[] {\n                  typeToOpenType(Long.class),\n                  typeToOpenType(Long.class),\n                  typeToOpenType(Long.class),\n                  new ArrayType<>(1, recordEntry)\n                });\n          } else {\n            return classToOpenTypes.get(c);\n          }\n        } else if (t instanceof ParameterizedType) {\n          ParameterizedType pt = (ParameterizedType) t;\n          Type rawType = pt.getRawType();\n          if (rawType instanceof Class) {\n            Class<?> rt = (Class<?>) rawType;\n            Type[] argTypes = pt.getActualTypeArguments();\n            if (Map.class.isAssignableFrom(rt)) {\n              OpenType<?> keyType = typeToOpenType(argTypes[0]);\n              OpenType<?> valueType = typeToOpenType(argTypes[1]);\n              if (keyType != null && valueType != null) {\n                CompositeType rowType =\n                    new CompositeType(\n                        \"Map\",\n                        \"Map of data\",\n                        new String[] {\"key\", \"value\"},\n                        new String[] {\"key\", \"value\"},\n                        new OpenType[] {keyType, valueType});\n                return new ArrayType<>(1, rowType);\n              }\n            }\n          }\n        }\n      } catch (OpenDataException ode) {\n        log.warn(\"Failed to convert type to OpenType\", ode);\n      }\n\n      // nothing seems working...\n      return null;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static Object convertToOpenTypeValue(OpenType<?> ot, Object value) {\n      if (ot instanceof SimpleType) {\n        if (value instanceof AtomicInteger) {\n          return ((AtomicInteger) value).get();\n        } else if (value instanceof AtomicLong) {\n          return ((AtomicLong) value).get();\n        } else {\n          return value;\n        }\n      } else if (ot instanceof CompositeType) {\n        //                System.err.println(\"!!! converting val of type \" +\n        // value.getClass().getName());\n        //                System.err.println(\"!!! is profiler: \" + (value instanceof Profiler));\n        //                System.err.println(\"!!! is mbean value provider: \" + (value instanceof\n        // Profiler.MBeanValueProvider));\n        if (value instanceof Profiler && value instanceof Profiler.MBeanValueProvider) {\n          CompositeType ct = (CompositeType) ot;\n          Profiler.MBeanValueProvider p = (Profiler.MBeanValueProvider) value;\n\n          Profiler.Snapshot snapshot = p.getMBeanValue();\n          //                    System.err.println(\"!!! snapshot == null :: \" + (snapshot == null));\n          if (snapshot == null) {\n            //                        System.err.println(\"!!! NULL snapshot\");\n            try {\n              return new CompositeDataSupport(\n                  ct,\n                  new String[] {\"startTime\", \"lastRefresh\", \"interval\", \"data\"},\n                  new Object[] {\n                    convertToOpenTypeValue(ct.getType(\"startTime\"), ((Profiler) p).START_TIME),\n                    convertToOpenTypeValue(ct.getType(\"lastRefresh\"), -1L),\n                    convertToOpenTypeValue(ct.getType(\"interval\"), 0L),\n                    new CompositeData[0]\n                  });\n            } catch (OpenDataException e) {\n              log.warn(\"Failed to create empty profiler snapshot composite data\", e);\n              return null;\n            }\n          }\n\n          //                    System.err.println(\"!!! Snapshot length: \" + snapshot.total.length);\n          CompositeData[] total = new CompositeData[snapshot.total.length];\n\n          long divider = snapshot.timeInterval * 1000000; // converting ms to ns divider\n          int index = 0;\n          for (Profiler.Record r : snapshot.total) {\n            try {\n              //                            System.err.println(\"!!! adding record: \" + r);\n              CompositeType at =\n                  (CompositeType) ((ArrayType<?>) ct.getType(\"data\")).getElementOpenType();\n              CompositeType rt = (CompositeType) at.getType(\"value\");\n              CompositeData recordData =\n                  new CompositeDataSupport(\n                      rt,\n                      new String[] {\n                        \"block\",\n                        \"invocations\",\n                        \"selfTime.total\",\n                        \"selfTime.percent\",\n                        \"selfTime.avg\",\n                        \"selfTime.max\",\n                        \"selfTime.min\",\n                        \"wallTime.total\",\n                        \"wallTime.percent\",\n                        \"wallTime.avg\",\n                        \"wallTime.max\",\n                        \"wallTime.min\"\n                      },\n                      new Object[] {\n                        r.blockName,\n                        r.invocations,\n                        r.selfTime,\n                        snapshot.timeInterval > 0\n                            ? ((double) r.selfTime / (double) divider) * 100\n                            : 0,\n                        r.selfTime / r.invocations,\n                        r.selfTimeMax,\n                        r.selfTimeMin == Long.MAX_VALUE ? 0 : r.selfTimeMin,\n                        r.wallTime,\n                        snapshot.timeInterval > 0\n                            ? ((double) r.wallTime / (double) divider) * 100\n                            : 0,\n                        r.wallTime / r.invocations,\n                        r.wallTimeMax,\n                        r.wallTimeMin\n                      });\n              total[index] =\n                  new CompositeDataSupport(\n                      at, new String[] {\"key\", \"value\"}, new Object[] {r.blockName, recordData});\n            } catch (Exception ode) {\n              log.warn(\"Failed to create record composite data\", ode);\n            }\n            index++;\n          }\n\n          CompositeData snapshotData = null;\n          try {\n            //                        System.err.println(\"!!! creating snapshot data\");\n            snapshotData =\n                new CompositeDataSupport(\n                    ct,\n                    new String[] {\"startTime\", \"lastRefresh\", \"interval\", \"data\"},\n                    new Object[] {\n                      convertToOpenTypeValue(ct.getType(\"startTime\"), ((Profiler) p).START_TIME),\n                      convertToOpenTypeValue(ct.getType(\"lastRefresh\"), snapshot.timeStamp),\n                      convertToOpenTypeValue(ct.getType(\"interval\"), snapshot.timeInterval),\n                      total\n                    });\n          } catch (Exception e) {\n            log.warn(\"Failed to create profiler snapshot composite data\", e);\n          }\n          //                    System.err.println(\"!!! data: \" + snapshot);\n          return snapshotData;\n        }\n      } else if (ot instanceof ArrayType) {\n        ArrayType<?> at = (ArrayType<?>) ot;\n        OpenType<?> et = at.getElementOpenType();\n        if (value instanceof Map && et instanceof CompositeType) {\n          CompositeType ct = (CompositeType) et;\n          Map<Object, Object> map = new HashMap<>((Map<Object, Object>) value);\n          CompositeData[] array = new CompositeData[map.size()];\n          OpenType<?> keyType = ct.getType(\"key\");\n          OpenType<?> valueType = ct.getType(\"value\");\n          int index = 0;\n          for (Map.Entry<Object, Object> entry : map.entrySet()) {\n            Map<String, Object> row = new HashMap<>();\n            row.put(\"key\", convertToOpenTypeValue(keyType, entry.getKey()));\n            row.put(\"value\", convertToOpenTypeValue(valueType, entry.getValue()));\n            try {\n              array[index] = new CompositeDataSupport(ct, row);\n            } catch (OpenDataException ode) {\n              log.warn(\"Failed to create map row composite data\", ode);\n            }\n            index++;\n          }\n          return array;\n        }\n      }\n      return value;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/BTraceRuntimeAccessImpl.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage org.openjdk.btrace.runtime;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.BTraceRuntimeBridge;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.handlers.ErrorHandler;\nimport org.openjdk.btrace.core.handlers.EventHandler;\nimport org.openjdk.btrace.core.handlers.ExitHandler;\nimport org.openjdk.btrace.core.handlers.LowMemoryHandler;\nimport org.openjdk.btrace.core.handlers.TimerHandler;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.core.extensions.ExtensionContext;\nimport org.openjdk.btrace.runtime.auxiliary.Auxiliary;\n\npublic final class BTraceRuntimeAccessImpl implements BTraceRuntimeAccess.Delegate {\n  private static final BTraceRuntimeAccessImpl INSTANCE = new BTraceRuntimeAccessImpl();\n\n  static final class RTWrapper {\n    private BTraceRuntime.Impl rt = null;\n\n    boolean set(BTraceRuntime.Impl other) {\n      if (rt != null && other != null) {\n        return false;\n      }\n      rt = other;\n      return true;\n    }\n\n    <T> T escape(Callable<T> c) {\n      BTraceRuntime.Impl oldRuntime = rt;\n      rt = null;\n      try {\n        return c.call();\n      } catch (Exception ignored) {\n      } finally {\n        if (oldRuntime != null) {\n          rt = oldRuntime;\n        }\n      }\n      return null;\n    }\n  }\n\n  static final class Accessor implements BTraceRuntime.BTraceRuntimeAccessor {\n    @Override\n    public BTraceRuntime.Impl getRt() {\n      BTraceRuntime.Impl current = getCurrent();\n      return current != null ? current : dummy;\n    }\n  }\n\n  // to be registered by BTraceRuntimeImpl implementation class\n  // should be treated as virtually immutable\n  private static volatile BTraceRuntime.Impl dummy = null;\n\n  protected static final ThreadLocal<RTWrapper> rt;\n\n  static {\n    rt = ThreadLocal.withInitial(RTWrapper::new);\n  }\n\n  // BTraceRuntime against BTrace class name\n  protected static final Map<String, BTraceRuntimeImplBase> runtimes = new ConcurrentHashMap<>();\n\n  // a set of all the client names connected so far\n  private static final Set<String> clients = java.util.concurrent.ConcurrentHashMap.newKeySet();\n\n  // BTrace Class object corresponding to this client; accessed from instrumented code\n  private Class clazz;\n\n  // instrumentation level field for each runtime; accessed from instrumented code\n  private Field level;\n\n  private final AtomicBoolean exitting = new AtomicBoolean(false);\n\n  private BTraceRuntimeAccessImpl() {}\n\n  public static void install() {\n    BTraceRuntimeAccess.install(INSTANCE);\n    // Register the runtime accessor immediately\n    // This triggers BTraceRuntimes class load if not already loaded, which sets up FACTORY\n    BTraceRuntimes.ensureAccessorRegistered();\n  }\n\n  /** Ensures the runtime accessor is registered. Must be called after BTraceRuntimes static init completes. */\n  public static void ensureRegistered(BTraceRuntimeImplFactory<?> factory) {\n    if (dummy == null) {\n      registerRuntimeAccessor(factory);\n    }\n  }\n\n  private static boolean isRuntimeAccessorRegistered() {\n    return dummy != null;\n  }\n\n  static void addRuntime(String className, BTraceRuntimeImplBase rt) {\n    runtimes.put(className, rt);\n  }\n\n  /**\n   * Look up a registered runtime by probe class name. The name is normalized via\n   * {@link #normalizeProbeName}, so hidden-class names with a\n   * {@code \"/0x...\"} suffix resolve to the plain name used at registration.\n   */\n  static BTraceRuntimeImplBase getRuntime(String probeName) {\n    return probeName == null ? null : runtimes.get(normalizeProbeName(probeName));\n  }\n\n  /**\n   * Drop the {@link BTraceRuntime.Impl} previously registered for {@code className}.\n   *\n   * <p>Releases the strong GC root the registry map holds on a runtime (and anything it\n   * transitively reaches — notably {@code Class<?>}, {@code MethodHandle}s, and its\n   * defining {@code ClassLoader}). Callers that create a runtime via\n   * {@code BTraceRuntimes.getRuntime(...)} and then abort <strong>must</strong> call this\n   * to avoid a permanent Metaspace / object leak.\n   */\n  static void removeRuntime(String className) {\n    runtimes.remove(className);\n  }\n\n  /** Enter method is called by every probed method just before the probe actions start. */\n  static boolean enterInternal(BTraceRuntime.Impl currentRt) {\n    BTraceRuntimeImplBase current = (BTraceRuntimeImplBase) currentRt;\n    if (current.isDisabled()) return false;\n    return rt.get().set(current);\n  }\n\n  static void leaveInternal() {\n    rt.get().set(null);\n  }\n\n  static String getClientNameInternal(String forClassName) {\n    int idx = forClassName.lastIndexOf('/');\n    if (idx > -1) {\n      forClassName =\n          Auxiliary.class.getPackage().getName().replace('.', '/')\n              + \"/\"\n              + forClassName.substring(idx + 1);\n    } else {\n      forClassName = Auxiliary.class.getPackage().getName().replace('.', '/') + \"/\" + forClassName;\n    }\n\n    if (!BTraceRuntimeAccess.isUniqueClientClassNames()) {\n      return forClassName;\n    }\n\n    String name = forClassName;\n    int suffix = 1;\n    while (clients.contains(name)) {\n      name = forClassName + \"$\" + (suffix++);\n    }\n    clients.add(name);\n    return name;\n  }\n\n  void shutdownCmdLine() {\n    exitting.set(true);\n  }\n\n  /**\n   * One instance of BTraceRuntime is created per-client. This forClass method creates it. Class\n   * passed is the preprocessed BTrace program of the client.\n   */\n  static BTraceRuntimeImplBase forClassInternal(\n      Class cl,\n      TimerHandler[] tHandlers,\n      EventHandler[] evHandlers,\n      ErrorHandler[] errHandlers,\n      ExitHandler[] eHandlers,\n      LowMemoryHandler[] lmHandlers) {\n    BTraceRuntimeImplBase runtime = runtimes.get(normalizeProbeName(cl.getName()));\n    runtime.init(cl, tHandlers, evHandlers, errHandlers, eHandlers, lmHandlers);\n    return runtime;\n  }\n\n  /**\n   * Strip the hidden-class suffix from a probe class name so it maps to the\n   * registry key used by {@link #addRuntime(String, BTraceRuntimeImplBase)}.\n   *\n   * <p>On JDK 15+, probes are defined via {@code Lookup.defineHiddenClass}. Hidden\n   * classes report their {@link Class#getName()} as {@code \"pkg.Name/0xNNNN...\"},\n   * where the suffix after the slash is assigned by the VM. The registry is keyed\n   * by the plain {@code \"pkg.Name\"} because that's the name the runtime is\n   * registered under, before defineClass runs. Plain class names never contain\n   * a {@code '/'}, so stripping from the first slash is safe on all paths.\n   */\n  static String normalizeProbeName(String rawName) {\n    int slash = rawName.indexOf('/');\n    return slash > 0 ? rawName.substring(0, slash) : rawName;\n  }\n\n  /**\n   * Utility to create a new ThreadLocal object. Called by preprocessed BTrace class to create\n   * ThreadLocal for each @TLS variable. Called from instrumented code.\n   *\n   * @param initValue Initial value. This value must be either a boxed primitive or {@linkplain\n   *     Cloneable}. In case a {@linkplain Cloneable} value is provided the value is never used\n   *     directly - instead, a new clone of the value is created per thread.\n   */\n  static ThreadLocal newThreadLocalInternal(Object initValue) {\n    return ThreadLocal.withInitial(\n        () -> {\n          if (initValue == null) return initValue;\n\n          if (initValue instanceof Cloneable) {\n            try {\n              Class<?> clz = initValue.getClass();\n              Method m = clz.getDeclaredMethod(\"clone\");\n              m.setAccessible(true);\n              return m.invoke(initValue);\n            } catch (Exception e) {\n              System.err.println(\"BTrace: Failed to clone TLS initial value: \" + e.getMessage());\n              return null;\n            }\n          }\n          return initValue;\n        });\n  }\n\n  /** Get the current thread BTraceRuntime instance if there is one. */\n  static BTraceRuntimeImplBase getCurrent() {\n    // During initialization, dummy may not be set yet - return null gracefully\n    if (!isRuntimeAccessorRegistered()) {\n      return null;\n    }\n    RTWrapper rtw = rt.get();\n    BTraceRuntime.Impl current = rtw != null ? rtw.rt : null;\n    current = current != null ? current : dummy;\n    return (BTraceRuntimeImplBase) current;\n  }\n\n  @SuppressWarnings(\"UnusedReturnValue\")\n  static <T> T doWithCurrent(Callable<T> callable) {\n    RTWrapper rtw = rt.get();\n    assert rtw != null : \"BTraceRuntime access not set up\";\n    return rtw.escape(callable);\n  }\n\n  void send(String msg) {\n    BTraceRuntimeImplBase rt = getCurrent();\n    if (rt != null) {\n      rt.send(msg);\n    }\n  }\n\n  void send(Command cmd) {\n    BTraceRuntimeImplBase rt = getCurrent();\n    if (rt != null) {\n      rt.send(cmd);\n    }\n  }\n\n  static void registerRuntimeAccessor(BTraceRuntimeImplFactory<?> factory) {\n    try {\n      // Get the default runtime from the factory (passed to avoid circular dependency)\n      dummy = factory != null ? factory.getDefault() : null;\n      Field fld = BTraceRuntime.class.getDeclaredField(\"rtAccessor\");\n      fld.setAccessible(true);\n      fld.set(null, new Accessor());\n    } catch (IllegalAccessException\n        | IllegalArgumentException\n        | NoSuchFieldException\n        | SecurityException e) {\n      System.err.println(\"BTrace: Failed to register runtime accessor: \" + e.getMessage());\n    }\n  }\n\n  @Override\n  public boolean enter(BTraceRuntimeBridge currentRt) {\n    if (!(currentRt instanceof BTraceRuntime.Impl)) {\n      return false;\n    }\n    return enterInternal((BTraceRuntime.Impl) currentRt);\n  }\n\n  @Override\n  public void leave() {\n    BTraceRuntimeAccessImpl.leaveInternal();\n  }\n\n  @Override\n  public BTraceRuntimeBridge forClass(\n      Class cl,\n      TimerHandler[] tHandlers,\n      EventHandler[] evHandlers,\n      ErrorHandler[] errHandlers,\n      ExitHandler[] eHandlers,\n      LowMemoryHandler[] lmHandlers) {\n    return BTraceRuntimeAccessImpl.forClassInternal(\n        cl, tHandlers, evHandlers, errHandlers, eHandlers, lmHandlers);\n  }\n\n  @Override\n  public ThreadLocal newThreadLocal(Object initValue) {\n    return BTraceRuntimeAccessImpl.newThreadLocalInternal(initValue);\n  }\n\n  @Override\n  public String getClientName(String forClassName) {\n    return BTraceRuntimeAccessImpl.getClientNameInternal(forClassName);\n  }\n\n  @Override\n  public ExtensionContext currentContext() {\n    RTWrapper wrapper = rt.get();\n    BTraceRuntimeImplBase current = wrapper != null ? (BTraceRuntimeImplBase) wrapper.rt : null;\n    if (current == null) return null;\n    return new ExtensionContextImpl(\n        current,\n        current.getClassName(),\n        SharedSettings.GLOBAL.getEffectivePermissions());\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/BTraceRuntimeImplBase.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.runtime;\n\nimport com.sun.management.HotSpotDiagnosticMXBean;\nimport org.jctools.queues.MessagePassingQueue;\nimport org.jctools.queues.MpmcArrayQueue;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.BTraceRuntimeBridge;\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.Profiler;\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.openjdk.btrace.core.comm.ErrorCommand;\nimport org.openjdk.btrace.core.comm.EventCommand;\nimport org.openjdk.btrace.core.comm.ExitCommand;\nimport org.openjdk.btrace.core.comm.GridDataCommand;\nimport org.openjdk.btrace.core.comm.MessageCommand;\nimport org.openjdk.btrace.core.comm.NumberDataCommand;\nimport org.openjdk.btrace.core.comm.NumberMapDataCommand;\nimport org.openjdk.btrace.core.comm.StringMapDataCommand;\nimport org.openjdk.btrace.core.extensions.Extension;\nimport org.openjdk.btrace.core.handlers.ErrorHandler;\nimport org.openjdk.btrace.core.handlers.EventHandler;\nimport org.openjdk.btrace.core.handlers.ExitHandler;\nimport org.openjdk.btrace.core.handlers.LowMemoryHandler;\nimport org.openjdk.btrace.core.handlers.TimerHandler;\nimport org.openjdk.btrace.runtime.profiling.MethodInvocationProfiler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.management.ListenerNotFoundException;\nimport javax.management.MBeanServer;\nimport javax.management.NotificationEmitter;\nimport javax.management.NotificationListener;\nimport javax.management.ObjectName;\nimport javax.management.openmbean.CompositeData;\nimport java.io.BufferedInputStream;\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.instrument.Instrumentation;\nimport java.lang.management.GarbageCollectorMXBean;\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.MemoryMXBean;\nimport java.lang.management.MemoryNotificationInfo;\nimport java.lang.management.MemoryPoolMXBean;\nimport java.lang.management.OperatingSystemMXBean;\nimport java.lang.management.RuntimeMXBean;\nimport java.lang.management.ThreadMXBean;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.net.URI;\nimport java.net.URL;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.security.AccessController;\nimport java.security.PrivilegedAction;\nimport java.security.PrivilegedExceptionAction;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.Collections;\nimport java.util.IdentityHashMap;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Base class form multiple Java version specific implementation.\n *\n * <p>Helper class used by BTrace built-in functions and also acts runtime \"manager\" for a specific\n * BTrace client and sends Commands to the CommandListener passed.\n *\n * @author A. Sundararajan\n * @author Christian Glencross (aggregation support)\n * @author Joachim Skeie (GC MBean support, advanced Deque manipulation)\n * @author KLynch\n */\n@SuppressWarnings(\"unchecked\")\npublic abstract class BTraceRuntimeImplBase implements BTraceRuntime.Impl, BTraceRuntimeBridge {\n  private static final Logger log = LoggerFactory.getLogger(BTraceRuntimeImplBase.class);\n\n  private static final String HOTSPOT_BEAN_NAME = \"com.sun.management:type=HotSpotDiagnostic\";\n\n  private static final int CMD_QUEUE_LIMIT_DEFAULT = 100;\n  private static int CMD_QUEUE_LIMIT;\n  private boolean shouldInitializeMBeans =\n      true; // mbean initialization guard; synchronized over *this*\n\n  /**\n   * Utility to create a new jvmstat perf counter. Called by preprocessed BTrace class to create\n   * perf counter for each @Export variable.\n   */\n  public abstract void newPerfCounter(Object value, String name, String desc);\n\n  /** Return the value of integer perf. counter of given name. */\n  public final int getPerfInt(String name) {\n    return (int) getPerfLong(name);\n  }\n\n  /** Write the value of integer perf. counter of given name. */\n  public final void putPerfInt(int value, String name) {\n    putPerfLong(value, name);\n  }\n\n  /** Return the value of float perf. counter of given name. */\n  public final float getPerfFloat(String name) {\n    int val = getPerfInt(name);\n    return Float.intBitsToFloat(val);\n  }\n\n  /** Write the value of float perf. counter of given name. */\n  public final void putPerfFloat(float value, String name) {\n    int i = Float.floatToRawIntBits(value);\n    putPerfInt(i, name);\n  }\n\n  /** Return the value of long perf. counter of given name. */\n  @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n  public final long getPerfLong(String name) {\n    ByteBuffer b = counters.get(name);\n    synchronized (b) {\n      long l = b.getLong();\n      b.rewind();\n      return l;\n    }\n  }\n\n  /** Write the value of float perf. counter of given name. */\n  @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n  public final void putPerfLong(long value, String name) {\n    ByteBuffer b = counters.get(name);\n    synchronized (b) {\n      b.putLong(value);\n      b.rewind();\n    }\n  }\n\n  /** Return the value of String perf. counter of given name. */\n  @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n  public final String getPerfString(String name) {\n    ByteBuffer b = counters.get(name);\n    byte[] buf = new byte[b.limit()];\n    byte t = 0;\n    int i = 0;\n    synchronized (b) {\n      while (b.hasRemaining() && (t = b.get()) != '\\0') {\n        buf[i++] = t;\n      }\n      b.rewind();\n    }\n    return new String(buf, 0, i, StandardCharsets.UTF_8);\n  }\n\n  /** Write the value of float perf. counter of given name. */\n  @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n  public final void putPerfString(String value, String name) {\n    ByteBuffer b = counters.get(name);\n    byte[] v = getStringBytes(value);\n    synchronized (b) {\n      b.put(v);\n      b.rewind();\n    }\n  }\n\n  private static final class ConsumerWrapper implements MessagePassingQueue.Consumer<Command> {\n    private final CommandListener cmdHandler;\n    private final AtomicBoolean exitSignal;\n\n    public ConsumerWrapper(CommandListener cmdHandler, AtomicBoolean exitSignal) {\n      this.cmdHandler = cmdHandler;\n      this.exitSignal = exitSignal;\n    }\n\n    @Override\n    public void accept(Command t) {\n      try {\n        cmdHandler.onCommand(t);\n      } catch (IOException e) {\n        log.warn(\"Command handler I/O error\", e);\n      }\n      if (t.getType() == Command.EXIT) {\n        exitSignal.set(true);\n      }\n    }\n  }\n\n  private static Properties dotWriterProps;\n  private static final boolean messageTimestamp = false;\n  // are we running with DTrace support enabled?\n  private static volatile boolean dtraceEnabled;\n\n  // Few MBeans used to implement certain built-in functions\n  private static volatile MemoryMXBean memoryMBean;\n  private static volatile List<MemoryPoolMXBean> memPoolList;\n  private static volatile HotSpotDiagnosticMXBean hotspotMBean;\n  private static volatile RuntimeMXBean runtimeMBean;\n  private static volatile ThreadMXBean threadMBean;\n  private static volatile List<GarbageCollectorMXBean> gcBeanList;\n  private static volatile OperatingSystemMXBean operatingSystemMXBean;\n\n  // Per-client state starts here.\n  // current thread's exception\n  private final ThreadLocal<Throwable> currentException = new ThreadLocal<>();\n\n  // \"command line\" args supplied by client\n  private final ArgsMap args;\n\n  // whether current runtime has been disabled?\n  protected volatile boolean disabled;\n\n  // Class object of the BTrace class [of this client]\n  private final String className;\n\n  // BTrace Class object corresponding to this client\n  private Class clazz;\n\n  /**\n   * The probe class (after {@link #init}) or {@code null}. Callers that need\n   * reflective access bypass {@link Class#forName}, which can't see probes\n   * defined in isolated or hidden class loaders.\n   */\n  Class<?> getProbeClass() {\n    return clazz;\n  }\n\n  // instrumentation level field for each runtime (legacy, may not exist).\n  // Only used for backward compatibility with old bytecode-based level checks.\n  // Primary storage is now in levelValue (see below).\n  private Field level;\n\n  // instrumentation level value (PRIMARY source of truth for level checking).\n  // This is the canonical level storage for MethodHandle-based guards.\n  // The legacy $btrace$$level field in the probe class is only updated for\n  // backward compatibility; level checking now happens at the MethodHandle layer.\n  // See HandlerRepositoryImpl.applyLevelGuard() for how this value is used.\n  private volatile int levelValue = 0;\n\n  // array of timer callback methods\n  private TimerHandler[] timerHandlers;\n  private EventHandler[] eventHandlers;\n  private ErrorHandler[] errorHandlers;\n  private ExitHandler[] exitHandlers;\n  private LowMemoryHandler[] lowMemoryHandlers;\n\n  // map of client event handling methods\n  private volatile Map<String, Method> eventHandlerMap;\n  private Map<String, LowMemoryHandler> lowMemoryHandlerMap;\n\n  // timer to run profile provider actions\n  private volatile Timer timer;\n\n  // executer to run low memory handlers\n  private volatile ExecutorService threadPool;\n  // Memory MBean listener\n  private volatile NotificationListener memoryListener;\n\n  // Extension registry for this runtime\n  // Extension instances are now resolved via the manifest-based bridge when injected.\n  private final Set<Extension> extensions = Collections.newSetFromMap(new IdentityHashMap<>());\n  private volatile boolean extensionsClosed = false;\n\n  // Command queue for the client\n  private final CommandQueue queue;\n\n  private static class SpeculativeQueueManager {\n    // maximum number of speculative buffers\n    private static final int MAX_SPECULATIVE_BUFFERS = Short.MAX_VALUE;\n    // per buffer message limit\n    private static final int MAX_SPECULATIVE_MSG_LIMIT = Short.MAX_VALUE;\n    // next speculative buffer id\n    private int nextSpeculationId;\n    // speculative buffers map\n    private ConcurrentHashMap<Integer, MpmcArrayQueue<Command>> speculativeQueues;\n    // per thread current speculative buffer id\n    private ThreadLocal<Integer> currentSpeculationId;\n\n    SpeculativeQueueManager() {\n      speculativeQueues = new ConcurrentHashMap<>();\n      currentSpeculationId = new ThreadLocal<>();\n    }\n\n    void clear() {\n      speculativeQueues.clear();\n      speculativeQueues = null;\n      currentSpeculationId.remove();\n      currentSpeculationId = null;\n    }\n\n    int speculation() {\n      int nextId = getNextSpeculationId();\n      if (nextId != -1) {\n        speculativeQueues.put(nextId, new MpmcArrayQueue<>(MAX_SPECULATIVE_MSG_LIMIT));\n      }\n      return nextId;\n    }\n\n    boolean send(Command cmd) {\n      if (currentSpeculationId != null) {\n        Integer curId = currentSpeculationId.get();\n        if ((curId != null) && (cmd.getType() != Command.EXIT)) {\n          MpmcArrayQueue<Command> sb = speculativeQueues.get(curId);\n          if (sb != null) {\n            if (!sb.offer(cmd)) {\n              sb.clear();\n              sb.offer(new MessageCommand(\"speculative buffer overflow: \" + curId));\n            }\n            return true;\n          }\n        }\n      }\n      return false;\n    }\n\n    void speculate(int id) {\n      validateId(id);\n      currentSpeculationId.set(id);\n    }\n\n    void commit(int id, CommandQueue result) {\n      validateId(id);\n      currentSpeculationId.set(null);\n      MpmcArrayQueue<Command> sb = speculativeQueues.get(id);\n      if (sb != null) {\n        result.addAll(sb);\n        sb.clear();\n        speculativeQueues.remove(id);\n      }\n    }\n\n    void discard(int id) {\n      validateId(id);\n      currentSpeculationId.set(null);\n      MpmcArrayQueue<Command> sb = speculativeQueues.get(id);\n      if (sb != null) {\n        sb.clear();\n        speculativeQueues.remove(id);\n      }\n    }\n\n    // -- Internals only below this point\n    private synchronized int getNextSpeculationId() {\n      if (nextSpeculationId == MAX_SPECULATIVE_BUFFERS) {\n        return -1;\n      }\n      return nextSpeculationId++;\n    }\n\n    private void validateId(int id) {\n      if (!speculativeQueues.containsKey(id)) {\n        throw new RuntimeException(\"invalid speculative buffer id: \" + id);\n      }\n    }\n  }\n  // per client speculative buffer manager\n  private final SpeculativeQueueManager specQueueManager;\n  // background thread that sends Commands to the handler\n  private volatile Thread cmdThread;\n  private final Instrumentation instrumentation;\n\n  private final AtomicBoolean exitting = new AtomicBoolean(false);\n  private final MessagePassingQueue.WaitStrategy waitStrategy =\n      i -> {\n        if (exitting.get()) return 0;\n        try {\n          if (i < 3000) {\n            Thread.yield();\n          } else if (i < 3100) {\n            Thread.sleep(1);\n          } else {\n            Thread.sleep(500);\n          }\n        } catch (InterruptedException e) {\n          return 0;\n        }\n        return i + 1;\n      };\n  private final MessagePassingQueue.ExitCondition exitCondition = () -> !exitting.get();\n\n  // jvmstat related stuff\n  // interface to read perf counters of this process\n  protected static final PerfReader perfReader = createPerfReaderImpl();\n  // performance counters created by this client\n  protected static final Map<String, ByteBuffer> counters = new ConcurrentHashMap<>();\n\n  private static final BTraceRuntimeImplFactory<BTraceRuntime.Impl> factory = null;\n\n  static {\n    setupCmdQueueParams();\n    loadLibrary(perfReader.getClass().getClassLoader());\n  }\n\n  BTraceRuntimeImplBase() {\n    args = null;\n    queue = null;\n    specQueueManager = null;\n    className = null;\n    instrumentation = null;\n  }\n\n  BTraceRuntimeImplBase(\n      String className, ArgsMap args, CommandListener cmdListener, Instrumentation inst) {\n    this.args = args;\n    queue = new CommandQueue(CMD_QUEUE_LIMIT);\n    specQueueManager = new SpeculativeQueueManager();\n    this.className = className;\n    instrumentation = inst;\n\n    BTraceRuntimeAccessImpl.addRuntime(className, this);\n\n    cmdThread =\n        new Thread(\n            () -> {\n              try {\n                enter();\n                queue.drain(\n                    new ConsumerWrapper(cmdListener, exitting), waitStrategy, exitCondition);\n              } finally {\n                queue.clear();\n                specQueueManager.clear();\n                leave();\n                disabled = true;\n              }\n            });\n    cmdThread.setDaemon(true);\n    cmdThread.start();\n  }\n\n  @Override\n  public final String getClassName() {\n    return className;\n  }\n\n  private static void setupCmdQueueParams() {\n    String maxQLen = System.getProperty(BTraceRuntime.CMD_QUEUE_LIMIT_KEY, null);\n    if (maxQLen == null) {\n      CMD_QUEUE_LIMIT = CMD_QUEUE_LIMIT_DEFAULT;\n    } else {\n      try {\n        CMD_QUEUE_LIMIT = Integer.parseInt(maxQLen);\n        if (log.isDebugEnabled()) {\n          log.debug(\"The cmd queue limit set to {}\", CMD_QUEUE_LIMIT);\n        }\n      } catch (NumberFormatException e) {\n        if (log.isDebugEnabled()) {\n          log.debug(\n              \"\\\"{}\\\" is not a valid int number. \" + \"Using the default cmd queue limit of {}\",\n              maxQLen,\n              CMD_QUEUE_LIMIT_DEFAULT);\n        }\n        CMD_QUEUE_LIMIT = CMD_QUEUE_LIMIT_DEFAULT;\n      }\n    }\n  }\n\n  final void init(\n      Class cl,\n      TimerHandler[] tHandlers,\n      EventHandler[] evHandlers,\n      ErrorHandler[] errHandlers,\n      ExitHandler[] eHandlers,\n      LowMemoryHandler[] lmHandlers) {\n    if (log.isDebugEnabled()) {\n      log.debug(\"init: clazz = {}, cl = {}\", clazz, cl);\n    }\n    if (clazz != null) {\n      return;\n    }\n\n    clazz = cl;\n\n    if (log.isDebugEnabled()) {\n      log.debug(\"init: timerHandlers = {}\", Arrays.deepToString(tHandlers));\n    }\n    timerHandlers = tHandlers;\n    eventHandlers = evHandlers;\n    errorHandlers = errHandlers;\n    exitHandlers = eHandlers;\n    lowMemoryHandlers = lmHandlers;\n\n    // Level is now stored on the runtime instance instead of the probe class field.\n    // This allows level checking to happen at MethodHandle linking time without relying\n    // on a bytecode-level field that was never properly initialized.\n    int levelVal = BTraceRuntime.parseInt(args.get(\"level\"), Integer.MIN_VALUE);\n    if (levelVal > Integer.MIN_VALUE) {\n      setLevel(levelVal);\n    }\n\n    // Attempt to set the legacy $btrace$$level field if it exists (for backward compatibility)\n    try {\n      level = cl.getDeclaredField(\"$btrace$$level\");\n      level.setAccessible(true);\n      if (levelVal > Integer.MIN_VALUE) {\n        level.set(null, levelVal);\n      }\n    } catch (Throwable e) {\n      log.debug(\"Instrumentation level field not available (this is OK with MethodHandle-based guards)\", e);\n    }\n\n    BTraceMBean.registerMBean(clazz);\n  }\n\n  /**\n   * start method is called by every BTrace (preprocesed) class just at the end of it's class\n   * initializer.\n   */\n  public final void start() {\n    initMBeans();\n    if (timerHandlers != null) {\n      try {\n        timer = new Timer(true);\n        TimerTask[] timerTasks = new TimerTask[timerHandlers.length];\n        wrapToTimerTasks(timerTasks);\n        for (int index = 0; index < timerHandlers.length; index++) {\n          TimerHandler th = timerHandlers[index];\n          long period = th.period;\n          String periodArg = th.periodArg;\n          if (periodArg != null) {\n            period = BTraceRuntime.parseLong(args.template(periodArg), period);\n          }\n          timer.schedule(timerTasks[index], period, period);\n        }\n      } catch (Exception e) {\n        log.error(\"Timer creation/scheduling failed\", e);\n      }\n    }\n\n    if (lowMemoryHandlers != null) {\n      lowMemoryHandlerMap = new HashMap<>();\n      for (LowMemoryHandler lmh : lowMemoryHandlers) {\n        String poolName = args.template(lmh.pool);\n        lowMemoryHandlerMap.put(poolName, lmh);\n      }\n      for (MemoryPoolMXBean mpoolBean : getMemoryPoolMXBeans()) {\n        String name = mpoolBean.getName();\n        LowMemoryHandler lmh = lowMemoryHandlerMap.get(name);\n        if (lmh != null) {\n          if (mpoolBean.isUsageThresholdSupported()) {\n            mpoolBean.setUsageThreshold(lmh.threshold);\n          }\n        }\n      }\n      NotificationEmitter emitter = (NotificationEmitter) memoryMBean;\n      emitter.addNotificationListener(memoryListener, null, null);\n    }\n\n    leave();\n  }\n\n  @Override\n  public final void handleEvent(Object cmd) {\n    if (!(cmd instanceof EventCommand)) {\n      return;\n    }\n    EventCommand ecmd = (EventCommand) cmd;\n    if (eventHandlers != null) {\n      Map<String, Method> localMap = eventHandlerMap;\n      if (localMap == null) {\n        synchronized (this) {\n          if (eventHandlerMap == null) {\n            Map<String, Method> m = new HashMap<>();\n            for (EventHandler eh : eventHandlers) {\n              try {\n                String eventName = args.template(eh.getEvent());\n                m.put(eventName, eh.getMethod(clazz));\n              } catch (NoSuchMethodException ignored) {\n              }\n            }\n            eventHandlerMap = m;\n            localMap = m;\n          } else {\n            localMap = eventHandlerMap;\n          }\n        }\n      }\n      String event = ecmd.getEvent();\n      event = event != null ? event : EventHandler.ALL_EVENTS;\n\n      Method eventHandler = localMap.get(event);\n      if (eventHandler != null) {\n        BTraceRuntimeAccessImpl.doWithCurrent(\n            (Callable<Void>)\n                () -> {\n                  eventHandler.invoke(null, (Object[]) null);\n                  return null;\n                });\n      }\n    }\n  }\n\n  @Override\n  public final int getInstrumentationLevel() {\n    BTraceRuntimeImplBase cur = getCurrent();\n\n    try {\n      return cur.getLevel();\n    } catch (Exception e) {\n      return 0;\n    }\n  }\n\n  @Override\n  public final void setInstrumentationLevel(int level) {\n    BTraceRuntimeImplBase cur = getCurrent();\n    try {\n      cur.setLevel(level);\n    } catch (Exception e) {\n      // ignore\n    }\n  }\n\n  public final void shutdownCmdLine() {\n    exitting.set(true);\n  }\n\n  /**\n   * Leave method is called by every probed method just before the probe actions end (and actual\n   * probed method continues).\n   */\n  @Override\n  public final void leave() {\n    BTraceRuntimeAccessImpl.leaveInternal();\n  }\n\n  /** Handles exception from BTrace probe actions. */\n  @Override\n  public final void handleException(Throwable th) {\n    if (currentException.get() != null) {\n      return;\n    }\n    boolean entered = BTraceRuntimeAccessImpl.enterInternal(this);\n    try {\n      currentException.set(th);\n\n      if (th instanceof ExitException) {\n        exitImpl(((ExitException) th).exitCode());\n      } else {\n        if (errorHandlers != null) {\n          for (ErrorHandler eh : errorHandlers) {\n            try {\n              eh.getMethod(clazz).invoke(null, th);\n            } catch (Throwable ignored) {\n            }\n          }\n        } else {\n          // Do not call send(Command). Exception messages should not\n          // go to speculative buffers!\n          enqueue(new ErrorCommand(th));\n        }\n      }\n    } finally {\n      currentException.set(null);\n      if (entered) {\n        leave();\n      }\n    }\n  }\n  // package-private interface to BTraceUtils class.\n\n  @Override\n  public final int speculation() {\n    return specQueueManager.speculation();\n  }\n\n  @Override\n  public final void speculate(int id) {\n    specQueueManager.speculate(id);\n  }\n\n  @Override\n  public final void discard(int id) {\n    specQueueManager.discard(id);\n  }\n\n  @Override\n  public final void commit(int id) {\n    specQueueManager.commit(id, queue);\n  }\n\n  @Override\n  public final long sizeof(Object obj) {\n    return instrumentation.getObjectSize(obj);\n  }\n\n  // BTrace command line argument functions\n  @Override\n  public final int $length() {\n    return args == null ? 0 : args.size();\n  }\n\n  @Override\n  public final String $(int n) {\n    if (args == null) {\n      return null;\n    } else {\n      return args.get(n);\n    }\n  }\n\n  @Override\n  public final String $(String key) {\n    BTraceRuntime.Impl runtime = getCurrent();\n    if (args == null) {\n      return null;\n    } else {\n      return args.get(key);\n    }\n  }\n\n  /**\n   * Returns the script arguments map.\n   *\n   * @return the args map, or null if no arguments\n   */\n  public final ArgsMap getArgsMap() {\n    return args;\n  }\n\n  // Direct access to extension implementations is not supported; services are injected via\n  // invokedynamic and resolved by the bridge.\n\n  // BTrace perf counter reading functions\n  @Override\n  public final int perfInt(String name) {\n    return getPerfReader().perfInt(name);\n  }\n\n  @Override\n  public final long perfLong(String name) {\n    return getPerfReader().perfLong(name);\n  }\n\n  @Override\n  public final String perfString(String name) {\n    return getPerfReader().perfString(name);\n  }\n\n  @Override\n  public final String toXML(Object obj) {\n    try {\n      return XMLSerializer.toXML(obj);\n    } catch (RuntimeException re) {\n      throw re;\n    } catch (Exception exp) {\n      throw new RuntimeException(exp);\n    }\n  }\n\n  @Override\n  public final void writeXML(Object obj, String fileName) {\n    try {\n      Path p = FileSystems.getDefault().getPath(resolveFileName(fileName));\n      try (BufferedWriter bw = Files.newBufferedWriter(p, StandardCharsets.UTF_8)) {\n        XMLSerializer.write(obj, bw);\n      }\n    } catch (RuntimeException re) {\n      throw re;\n    } catch (Exception exp) {\n      throw new RuntimeException(exp);\n    }\n  }\n\n  private static synchronized void initDOTWriterProps() {\n    if (dotWriterProps == null) {\n      dotWriterProps = new Properties();\n      InputStream is =\n          BTraceRuntime.class.getResourceAsStream(\"resources/btrace.dotwriter.properties\");\n      if (is != null) {\n        try {\n          dotWriterProps.load(is);\n        } catch (IOException ioExp) {\n          log.warn(\"Failed to load DOTWriter properties from classpath\", ioExp);\n        }\n      }\n      try {\n        String home = System.getProperty(\"user.home\");\n        File file = new File(home, \"btrace.dotwriter.properties\");\n        if (file.exists() && file.isFile()) {\n          is = new BufferedInputStream(new FileInputStream(file));\n          dotWriterProps.load(is);\n        }\n      } catch (Exception exp) {\n        log.warn(\"Failed to load DOTWriter properties from user home\", exp);\n      }\n    }\n  }\n\n  @Override\n  public final void writeDOT(Object obj, String fileName) {\n    DOTWriter writer = new DOTWriter(resolveFileName(fileName));\n    initDOTWriterProps();\n    writer.customize(dotWriterProps);\n    writer.addNode(null, obj);\n    writer.close();\n  }\n\n  // profiling related methods\n  /**\n   * @see BTraceUtils.Profiling#newProfiler()\n   */\n  @Override\n  public final Profiler newProfiler() {\n    return new MethodInvocationProfiler(600);\n  }\n\n  /**\n   * @see BTraceUtils.Profiling#newProfiler(int)\n   */\n  @Override\n  public final Profiler newProfiler(int expectedMethodCnt) {\n    return new MethodInvocationProfiler(expectedMethodCnt);\n  }\n\n  @Override\n  public final RuntimeMXBean getRuntimeMXBean() {\n    initMBeans();\n    return runtimeMBean;\n  }\n\n  @Override\n  public final ThreadMXBean getThreadMXBean() {\n    initMBeans();\n    return threadMBean;\n  }\n\n  @Override\n  public final OperatingSystemMXBean getOperatingSystemMXBean() {\n    initMBeans();\n    return operatingSystemMXBean;\n  }\n\n  @Override\n  public final List<GarbageCollectorMXBean> getGCMBeans() {\n    initMBeans();\n    return gcBeanList;\n  }\n\n  @Override\n  public final HotSpotDiagnosticMXBean getHotspotMBean() {\n    initMBeans();\n    return hotspotMBean;\n  }\n\n  public final boolean isDisabled() {\n    return disabled;\n  }\n\n  @Override\n  public final boolean enter() {\n    return BTraceRuntimeAccessImpl.enterInternal(this);\n  }\n\n  @Override\n  public final void handleExit(int exitCode) {\n    cleanupExtensions();\n    exitImpl(exitCode);\n    try {\n      // Use timeout to prevent indefinite blocking during shutdown\n      // Don't interrupt - let cmdThread finish processing remaining commands\n      cmdThread.join(2000);\n    } catch (InterruptedException e) {\n      Thread.currentThread().interrupt();\n    }\n    cleanupRuntime();\n  }\n\n  public final int getLevel() {\n    // First try to read from the probe class field (legacy, for backward compatibility)\n    if (level != null) {\n      try {\n        return (int) level.get(null);\n      } catch (IllegalAccessException e) {\n        // Field exists but cannot be accessed; use fallback\n        log.debug(\"Cannot access legacy level field, using runtime value\", e);\n      }\n    }\n    // Fall back to runtime-stored level value (primary source)\n    return levelValue;\n  }\n\n  public final void setLevel(int level) {\n    // Always store in runtime value field (primary source)\n    this.levelValue = level;\n    // Also try to set on probe class field if it exists (legacy, for backward compatibility)\n    if (this.level != null) {\n      try {\n        this.level.set(null, level);\n      } catch (IllegalAccessException e) {\n        // Field exists but cannot be accessed; that's okay, levelValue is primary\n        log.debug(\"Cannot update legacy level field (will use runtime value)\", e);\n      }\n    }\n  }\n\n  protected void cleanupRuntime() {\n    // to be overridden by concrete implementations\n  }\n\n  final void registerExtension(Extension ext) {\n    if (ext == null) {\n      return;\n    }\n    synchronized (extensions) {\n      extensions.add(ext);\n    }\n  }\n\n  private void cleanupExtensions() {\n    if (extensionsClosed) {\n      return;\n    }\n    synchronized (extensions) {\n      if (extensionsClosed) {\n        return;\n      }\n      extensionsClosed = true;\n      for (Extension ext : extensions) {\n        try {\n          ext.close();\n        } catch (Throwable ignore) {\n          // best effort cleanup\n        }\n      }\n      extensions.clear();\n    }\n  }\n\n  protected static void loadLibrary(ClassLoader cl) {\n    AccessController.doPrivileged(\n        (PrivilegedAction<Void>)\n            () -> {\n              loadBTraceLibrary(cl);\n              return null;\n            });\n  }\n\n  private static void loadBTraceLibrary(ClassLoader loader) {\n    boolean isSolaris = System.getProperty(\"os.name\").equals(\"SunOS\");\n    if (isSolaris) {\n      try {\n        System.loadLibrary(\"btrace\");\n        dtraceEnabled = true;\n      } catch (LinkageError le) {\n        URL btracePkg = null;\n        if (loader != null) {\n          btracePkg = loader.getResource(\"org/openjdk/btrace\");\n        }\n\n        if (btracePkg == null) {\n          log.debug(\"cannot load libbtrace.so, will miss DTrace probes from BTrace\");\n          return;\n        }\n\n        String path = btracePkg.toString();\n        int archSeparator = path.indexOf('!');\n        if (archSeparator != -1) {\n          path = path.substring(0, archSeparator);\n          path = path.substring(\"jar:\".length(), path.lastIndexOf('/'));\n        } else {\n          int buildSeparator = path.indexOf(\"/classes/\");\n          if (buildSeparator != -1) {\n            path = path.substring(0, buildSeparator);\n          }\n        }\n        String cpu = System.getProperty(\"os.arch\");\n        if (cpu.equals(\"x86\")) {\n          cpu = \"i386\";\n        }\n        path += \"/\" + cpu + \"/libbtrace.so\";\n        try {\n          path = new File(new URI(path)).getAbsolutePath();\n        } catch (RuntimeException re) {\n          throw re;\n        } catch (Exception e) {\n          throw new RuntimeException(e);\n        }\n        try {\n          System.load(path);\n          dtraceEnabled = true;\n        } catch (LinkageError le1) {\n          log.debug(\"cannot load libbtrace.so, will miss DTrace probes from BTrace\");\n        }\n      }\n    }\n  }\n\n  private BTraceRuntimeImplBase getCurrent() {\n    return BTraceRuntimeAccessImpl.getCurrent();\n  }\n\n  private void initThreadPool() {\n    threadPool =\n        Executors.newFixedThreadPool(\n            1,\n            r -> {\n              Thread th = new Thread(r, \"BTrace Worker\");\n              th.setDaemon(true);\n              return th;\n            });\n  }\n\n  /** Must be called exactly once before the runtime starts */\n  private synchronized void initMBeans() {\n    if (shouldInitializeMBeans) {\n      initMemoryMBean();\n      initOperatingSystemMBean();\n      initRuntimeMBean();\n      initThreadMBean();\n      initHotspotMBean();\n      initGcMBeans();\n      initMemoryPoolList();\n      initMemoryListener();\n      shouldInitializeMBeans = false;\n    }\n  }\n\n  private void initMemoryListener() {\n    initThreadPool();\n    memoryListener =\n        (notif, handback) -> {\n          boolean entered = enter();\n          try {\n            String notifType = notif.getType();\n            if (notifType.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) {\n              CompositeData cd = (CompositeData) notif.getUserData();\n              MemoryNotificationInfo info = MemoryNotificationInfo.from(cd);\n              String name = info.getPoolName();\n              LowMemoryHandler handler = lowMemoryHandlerMap.get(name);\n              if (handler != null) {\n                threadPool.submit(\n                    new Runnable() {\n                      @Override\n                      public void run() {\n                        boolean entered = enter();\n                        try {\n                          if (handler.trackUsage) {\n                            handler.invoke(clazz, null, info.getUsage());\n                          } else {\n                            handler.invoke(clazz, null, null);\n                          }\n                        } catch (Throwable th) {\n                        } finally {\n                          if (entered) {\n                            BTraceRuntime.leave();\n                          }\n                        }\n                      }\n                    });\n              }\n            }\n          } finally {\n            if (entered) {\n              BTraceRuntime.leave();\n            }\n          }\n        };\n  }\n\n  @Override\n  public final void send(String msg) {\n    send(new MessageCommand(messageTimestamp ? System.nanoTime() : 0L, msg));\n  }\n\n  @Override\n  public final void sendCommand(Object cmd) {\n    if (cmd instanceof Command) {\n      send((Command) cmd);\n    }\n  }\n\n  @Override\n  public final void sendNumberData(String name, Number value) {\n    send(new NumberDataCommand(name, value));\n  }\n\n  @Override\n  public final void sendNumberMapData(String name, Map<String, ? extends Number> data) {\n    send(new NumberMapDataCommand(name, data));\n  }\n\n  @Override\n  public final void sendStringMapData(String name, Map<String, String> data) {\n    send(new StringMapDataCommand(name, data));\n  }\n\n  @Override\n  public final void sendGridData(String name, List<Object[]> data) {\n    send(new GridDataCommand(name, data));\n  }\n\n  @Override\n  public final void sendGridData(String name, List<Object[]> data, String format) {\n    send(new GridDataCommand(name, data, format));\n  }\n\n  public final void send(Command cmd) {\n    boolean speculated = specQueueManager.send(cmd);\n    if (!speculated) {\n      enqueue(cmd);\n    }\n  }\n\n  private void enqueue(Command cmd) {\n    if (queue != null) {\n      queue.enqueue(cmd);\n    }\n  }\n\n  private void wrapToTimerTasks(TimerTask[] tasks) {\n    for (int index = 0; index < timerHandlers.length; index++) {\n      TimerHandler th = timerHandlers[index];\n      tasks[index] =\n          new TimerTask() {\n            final Method mthd;\n\n            {\n              Method m = null;\n              try {\n                m = th.getMethod(clazz);\n              } catch (Throwable t) {\n                log.warn(\"Failed to acquire timer handler method\", t);\n              }\n              mthd = m;\n            }\n\n            @Override\n            public void run() {\n              if (mthd != null) {\n                try {\n                  mthd.invoke(null, (Object[]) null);\n                } catch (Throwable th) {\n                  log.warn(\"Timer task execution failed\", th);\n                }\n              }\n            }\n          };\n    }\n  }\n\n  @Override\n  public final void exit(int exitCode) {\n    exitImpl(exitCode);\n  }\n\n  private synchronized void exitImpl(int exitCode) {\n    boolean entered = enter();\n    try {\n      if (timer != null) {\n        timer.cancel();\n      }\n\n      if (memoryListener != null && memoryMBean != null) {\n        NotificationEmitter emitter = (NotificationEmitter) memoryMBean;\n        try {\n          emitter.removeNotificationListener(memoryListener);\n        } catch (ListenerNotFoundException ignored) {\n        }\n      }\n\n      if (threadPool != null) {\n        threadPool.shutdownNow();\n      }\n\n      if (exitHandlers != null) {\n        for (ExitHandler eh : exitHandlers) {\n          try {\n            eh.getMethod(clazz).invoke(null, exitCode);\n          } catch (Throwable ignored) {\n          }\n        }\n        exitHandlers = null;\n      }\n\n      cleanupExtensions();\n      send(new ExitCommand(exitCode));\n    } finally {\n      disabled = true;\n      if (entered) {\n        BTraceRuntime.leave();\n      }\n    }\n  }\n\n  @Override\n  public final String resolveFileName(String name) {\n    if (name.indexOf(File.separatorChar) != -1) {\n      throw new IllegalArgumentException(\"directories are not allowed\");\n    }\n    StringBuilder buf = new StringBuilder();\n    buf.append('.');\n    buf.append(File.separatorChar);\n    buf.append(\"btrace\");\n    if (args != null && args.size() > 0) {\n      String arg0 = args.get(0);\n      String sanitized = sanitizePathSegment(arg0);\n      if (!sanitized.isEmpty()) {\n        buf.append(sanitized);\n      }\n    }\n    buf.append(File.separatorChar);\n    buf.append(className);\n    new File(buf.toString()).mkdirs();\n    buf.append(File.separatorChar);\n    buf.append(name);\n    return buf.toString();\n  }\n\n  private static String sanitizePathSegment(String s) {\n    if (s == null) return \"\";\n    // replace path separators and control chars with underscore; allow alnum, dash, underscore, dot\n    String sanitized = s.replace(File.separatorChar, '_').replace('/', '_').replace('\\\\', '_');\n    sanitized = sanitized.replaceAll(\"[^a-zA-Z0-9._-]\", \"_\");\n    // collapse multiple underscores\n    sanitized = sanitized.replaceAll(\"_+\", \"_\");\n    return sanitized;\n  }\n\n  private static void initMemoryPoolList() {\n    try {\n      memPoolList =\n          AccessController.doPrivileged(\n              (PrivilegedExceptionAction<List<MemoryPoolMXBean>>)\n                  ManagementFactory::getMemoryPoolMXBeans);\n    } catch (Exception exp) {\n      throw new UnsupportedOperationException(exp);\n    }\n  }\n\n  private static void initMemoryMBean() {\n    try {\n      memoryMBean =\n          AccessController.doPrivileged(\n              (PrivilegedExceptionAction<MemoryMXBean>) ManagementFactory::getMemoryMXBean);\n    } catch (Exception exp) {\n      throw new UnsupportedOperationException(exp);\n    }\n  }\n\n  private static void initOperatingSystemMBean() {\n    try {\n      operatingSystemMXBean =\n          AccessController.doPrivileged(\n              (PrivilegedExceptionAction<OperatingSystemMXBean>)\n                  ManagementFactory::getOperatingSystemMXBean);\n    } catch (Exception e) {\n      throw new UnsupportedOperationException(e);\n    }\n  }\n\n  private static void initRuntimeMBean() {\n    try {\n      runtimeMBean =\n          AccessController.doPrivileged(\n              (PrivilegedExceptionAction<RuntimeMXBean>) ManagementFactory::getRuntimeMXBean);\n    } catch (Exception e) {\n      throw new RuntimeException(e);\n    }\n  }\n\n  private static void initThreadMBean() {\n    try {\n      threadMBean =\n          AccessController.doPrivileged(\n              (PrivilegedExceptionAction<ThreadMXBean>) ManagementFactory::getThreadMXBean);\n    } catch (Exception e) {\n      throw new RuntimeException(e);\n    }\n  }\n\n  private static void initGcMBeans() {\n    try {\n      gcBeanList =\n          AccessController.doPrivileged(\n              (PrivilegedExceptionAction<List<GarbageCollectorMXBean>>)\n                  ManagementFactory::getGarbageCollectorMXBeans);\n    } catch (Exception e) {\n      throw new RuntimeException(e);\n    }\n  }\n\n  private static void initHotspotMBean() {\n    try {\n      hotspotMBean =\n          AccessController.doPrivileged(\n              (PrivilegedExceptionAction<HotSpotDiagnosticMXBean>)\n                  () -> {\n                    MBeanServer server = ManagementFactory.getPlatformMBeanServer();\n                    Set<ObjectName> s = server.queryNames(new ObjectName(HOTSPOT_BEAN_NAME), null);\n                    Iterator<ObjectName> itr = s.iterator();\n                    if (itr.hasNext()) {\n                      ObjectName name = itr.next();\n                      return ManagementFactory.newPlatformMXBeanProxy(\n                          server, name.toString(), HotSpotDiagnosticMXBean.class);\n                    } else {\n                      return null;\n                    }\n                  });\n    } catch (Exception e) {\n      throw new UnsupportedOperationException(e);\n    }\n  }\n\n  @Override\n  public boolean isDTraceEnabled() {\n    return dtraceEnabled;\n  }\n\n  @Override\n  public List<MemoryPoolMXBean> getMemoryPoolMXBeans() {\n    initMBeans();\n    return memPoolList;\n  }\n\n  @Override\n  public MemoryMXBean getMemoryMXBean() {\n    initMBeans();\n    return memoryMBean;\n  }\n\n  @SuppressWarnings(\"SameReturnValue\")\n  protected static PerfReader getPerfReader() {\n    return perfReader;\n  }\n\n  protected static byte[] getStringBytes(String value) {\n    byte[] v = null;\n    v = value.getBytes(StandardCharsets.UTF_8);\n    byte[] v1 = new byte[v.length + 1];\n    System.arraycopy(v, 0, v1, 0, v.length);\n    v1[v.length] = '\\0';\n    return v1;\n  }\n\n  @SuppressWarnings(\"LiteralClassName\")\n  private static PerfReader createPerfReaderImpl() {\n    // see if we can access any jvmstat class\n    try {\n      if (String.class.getResource(\"sun/jvmstat/monitor/MonitoredHost.class\") != null) {\n        return (PerfReader)\n            Class.forName(\"org.openjdk.btrace.agent.PerfReaderImpl\")\n                .getDeclaredConstructor()\n                .newInstance();\n      }\n    } catch (Exception exp) {\n      // can happen if jvmstat is not available\n    }\n    // no luck, create null implementation\n    return new NullPerfReaderImpl();\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/BTraceRuntimeImplFactory.java",
    "content": "package org.openjdk.btrace.runtime;\n\nimport java.lang.instrument.Instrumentation;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.comm.CommandListener;\n\npublic abstract class BTraceRuntimeImplFactory<T extends BTraceRuntime.Impl> {\n  private final T defaultRuntime;\n\n  protected BTraceRuntimeImplFactory(T defaultRuntime) {\n    this.defaultRuntime = defaultRuntime;\n  }\n\n  public final T getDefault() {\n    return defaultRuntime;\n  }\n\n  public abstract T getRuntime(\n      String className, ArgsMap args, CommandListener cmdListener, Instrumentation inst);\n\n  public abstract boolean isEnabled();\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/BTraceRuntimeImpl_8.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.runtime;\n\nimport java.lang.instrument.Instrumentation;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.security.AccessController;\nimport java.util.Set;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\nimport sun.misc.Perf;\nimport sun.misc.Unsafe;\nimport sun.reflect.CallerSensitive;\nimport sun.reflect.Reflection;\n\n/**\n * Helper class used by BTrace built-in functions and also acts runtime \"manager\" for a specific\n * BTrace client and sends Commands to the CommandListener passed.\n *\n * @author A. Sundararajan\n * @author Christian Glencross (aggregation support)\n * @author Joachim Skeie (GC MBean support, advanced Deque manipulation)\n * @author KLynch\n */\n@SuppressWarnings(\"deprecation\")\npublic final class BTraceRuntimeImpl_8 extends BTraceRuntimeImplBase {\n  public static final class Factory extends BTraceRuntimeImplFactory<BTraceRuntimeImpl_8> {\n    public Factory() {\n      super(new BTraceRuntimeImpl_8());\n    }\n\n    @Override\n    public BTraceRuntimeImpl_8 getRuntime(\n        String className, ArgsMap args, CommandListener cmdListener, Instrumentation inst) {\n      return new BTraceRuntimeImpl_8(className, args, cmdListener, inst);\n    }\n\n    @Override\n    public boolean isEnabled() {\n      try {\n        Class.forName(\"java.lang.Module\");\n        return false;\n      } catch (ClassNotFoundException ignored) {\n      }\n      return true;\n    }\n  }\n\n  // perf counter variability - we always variable variability\n  private static final int V_Variable = 3;\n  // perf counter units\n  private static final int V_None = 1;\n  private static final int V_String = 5;\n  private static final int PERF_STRING_LIMIT = 256;\n\n  private final Set<JfrEventFactoryImpl> eventFactories;\n\n  private static Perf perf;\n\n  private final boolean hasJfr;\n\n  private final Method findBootstrapOrNullMtd;\n\n  public BTraceRuntimeImpl_8() {\n    boolean jfr = false;\n    try {\n      Class.forName(\"jdk.jfr.Event\");\n      jfr = true;\n    } catch (Throwable t) {\n    }\n    hasJfr = jfr;\n    eventFactories = hasJfr ? new java.util.concurrent.CopyOnWriteArraySet<>() : null;\n\n    Method m = null;\n    try {\n      m = ClassLoader.class.getDeclaredMethod(\"findBootstrapClassOrNull\", String.class);\n      m.setAccessible(true);\n    } catch (NoSuchMethodException | RuntimeException ignored) {}\n    findBootstrapOrNullMtd = m;\n  }\n\n  public BTraceRuntimeImpl_8(\n      String className, ArgsMap args, CommandListener cmdListener, Instrumentation inst) {\n    super(className, args, cmdListener, inst);\n    boolean jfr = false;\n    try {\n      Class.forName(\"jdk.jfr.Event\");\n      jfr = true;\n    } catch (Throwable t) {\n    }\n    hasJfr = jfr;\n    eventFactories = hasJfr ? new java.util.concurrent.CopyOnWriteArraySet<>() : null;\n\n    Method m = null;\n    try {\n      m = ClassLoader.class.getDeclaredMethod(\"findBootstrapClassOrNull\", String.class);\n      m.setAccessible(true);\n    } catch (NoSuchMethodException | RuntimeException ignored) {}\n    findBootstrapOrNullMtd = m;\n  }\n\n  @Override\n  public Class<?> defineClass(byte[] code) {\n    Unsafe unsafe = BTraceRuntime.initUnsafe();\n    if (unsafe != null) {\n      // Use stack trace instead of Reflection.getCallerClass() to avoid\n      // CallerSensitive annotation requirement (only works from bootstrap CL)\n      StackTraceElement[] stack = Thread.currentThread().getStackTrace();\n      // stack[0] = getStackTrace, stack[1] = defineClass (this method), stack[2] = caller\n      String callerClassName = stack.length > 2 ? stack[2].getClassName() : null;\n      if (callerClassName == null || !callerClassName.startsWith(\"org.openjdk.btrace.\")) {\n        throw new SecurityException(\"unsafe defineClass\");\n      }\n      // Always define the probe in a fresh, isolated ClassLoader parented to the app CL.\n      // This makes the probe class unloadable once the probe's MethodHandles and its\n      // BTraceProbe.probeClass reference are cleared on unregister, while allowing the\n      // probe to access BTraceUtils and other agent classes.\n      ClassLoader parent = BTraceRuntimeImpl_8.class.getClassLoader();\n      if (parent == null) {\n        parent = Thread.currentThread().getContextClassLoader();\n      }\n      ClassLoader loader = new ClassLoader(parent) {};\n      Class<?> cl = unsafe.defineClass(getClassName(), code, 0, code.length, loader, null);\n      unsafe.ensureClassInitialized(cl);\n      return cl;\n    }\n\n    return null;\n  }\n\n  @Override\n  public void newPerfCounter(Object value, String name, String desc) {\n    Perf perf = getPerf();\n    char tc = desc.charAt(0);\n    switch (tc) {\n      case 'C':\n      case 'Z':\n      case 'B':\n      case 'S':\n      case 'I':\n      case 'J':\n      case 'F':\n      case 'D':\n        {\n          long initValue = (value != null) ? ((Number) value).longValue() : 0L;\n          ByteBuffer b = perf.createLong(name, V_Variable, V_None, initValue);\n          b.order(ByteOrder.nativeOrder());\n          counters.put(name, b);\n        }\n        break;\n\n      case '[':\n        break;\n      case 'L':\n        {\n          if (desc.equals(\"Ljava/lang/String;\")) {\n            byte[] buf;\n            if (value != null) {\n              buf = getStringBytes((String) value);\n            } else {\n              buf = new byte[PERF_STRING_LIMIT];\n              buf[0] = '\\0';\n            }\n            ByteBuffer b = perf.createByteArray(name, V_Variable, V_String, buf, buf.length);\n            counters.put(name, b);\n          }\n        }\n        break;\n    }\n  }\n\n  @CallerSensitive\n  @Override\n  public ClassLoader getCallerClassLoader(int stackDec) {\n    Class<?> c = Reflection.getCallerClass(stackDec + 1);\n    // Probe handlers run in the bootstrap CL as\n    // org.openjdk.btrace.runtime.auxiliary.* classes (INDY dispatch).\n    // Skip that frame to find the real application caller, mirroring\n    // BTraceRuntimeImpl_9's StackWalker skip of auxiliary.* frames.\n    if (c != null && c.getName().startsWith(\"org.openjdk.btrace.runtime.auxiliary.\")) {\n      c = Reflection.getCallerClass(stackDec + 2);\n    }\n    return c != null ? c.getClassLoader() : null;\n  }\n\n  @CallerSensitive\n  @Override\n  public Class<?> getCallerClass(int stackDec) {\n    Class<?> c = Reflection.getCallerClass(stackDec + 1);\n    if (c != null && c.getName().startsWith(\"org.openjdk.btrace.runtime.auxiliary.\")) {\n      c = Reflection.getCallerClass(stackDec + 2);\n    }\n    return c;\n  }\n\n  @Override\n  public JfrEvent.Factory createEventFactory(JfrEvent.Template template) {\n    if (hasJfr) {\n      JfrEventFactoryImpl factory = new JfrEventFactoryImpl(template);\n      eventFactories.add(factory);\n      return factory;\n    }\n    return () -> JfrEvent.EMPTY;\n  }\n\n  @Override\n  public boolean isBootstrapClass(String className) {\n    try {\n      return findBootstrapOrNullMtd != null && findBootstrapOrNullMtd.invoke(ClassLoader.getSystemClassLoader(), className) != null;\n    } catch (IllegalAccessException | InvocationTargetException ignored) {}\n    return false;\n  }\n\n  @Override\n  protected void cleanupRuntime() {\n    if (hasJfr) {\n      for (JfrEventFactoryImpl factory : eventFactories) {\n        factory.unregister();\n      }\n      eventFactories.clear();\n    }\n  }\n\n  @Override\n  public int version() {\n    return 7;\n  }\n\n  private static Perf getPerf() {\n    synchronized (BTraceRuntimeImpl_8.class) {\n      if (perf == null) {\n        perf = AccessController.doPrivileged(new Perf.GetPerfAction());\n      }\n    }\n    return perf;\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/BTraceRuntimes.java",
    "content": "package org.openjdk.btrace.runtime;\n\nimport java.lang.instrument.Instrumentation;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic final class BTraceRuntimes {\n  private static final Logger log = LoggerFactory.getLogger(BTraceRuntimes.class);\n\n  private static BTraceRuntimeImplFactory<?> FACTORY = null;\n\n  static {\n    boolean loaded =\n        loadFactory(\"org.openjdk.btrace.runtime.BTraceRuntimeImpl_11$Factory\")\n            || loadFactory(\"org.openjdk.btrace.runtime.BTraceRuntimeImpl_9$Factory\")\n            || loadFactory(\"org.openjdk.btrace.runtime.BTraceRuntimeImpl_8$Factory\");\n    log.debug(\"BTraceRuntime loaded: {}\", loaded);\n    BTraceRuntimeAccessImpl.install();\n  }\n\n  private static boolean loadFactory(String className) {\n    try {\n      log.debug(\"Attempting to load BTrace runtime implementation: {}\", className);\n      ClassLoader[] loaders = new ClassLoader[] {\n          Thread.currentThread().getContextClassLoader(),\n          BTraceRuntimes.class.getClassLoader(),\n          ClassLoader.getSystemClassLoader()\n      };\n      for (ClassLoader loader : loaders) {\n        if (loader == null) continue;\n        try {\n          @SuppressWarnings(\"unchecked\") // generic cast due to dynamic classloading of a known API type\n          Class<BTraceRuntimeImplFactory<?>> factoryClz =\n              (Class<BTraceRuntimeImplFactory<?>>) loader.loadClass(className);\n          BTraceRuntimeImplFactory<?> instance = factoryClz.getConstructor().newInstance();\n          if (instance.isEnabled()) {\n            FACTORY = instance;\n            log.debug(\"BTrace runtime implementation {} loaded via {}\", className, loader);\n            return true;\n          }\n        } catch (ClassNotFoundException | UnsupportedClassVersionError e) {\n          // try next loader\n          if (log.isDebugEnabled()) {\n            log.debug(\"Loader {} could not load {}: {}\", loader, className, e.toString());\n          }\n        }\n      }\n    } catch (Exception e) {\n      log.error(\"Failed to load BTrace runtime implementation: {}\", className, e);\n    }\n    return false;\n  }\n\n  public static BTraceRuntime.Impl getDefault() {\n    // Ensure runtime accessor is registered (must be done after static init completes)\n    BTraceRuntimeAccessImpl.ensureRegistered(FACTORY);\n    return FACTORY != null ? FACTORY.getDefault() : null;\n  }\n\n  /**\n   * Ensures the runtime accessor is registered in BTraceRuntime.\n   * This must be called after getDefault() to complete initialization.\n   */\n  public static void ensureAccessorRegistered() {\n    BTraceRuntimeAccessImpl.ensureRegistered(FACTORY);\n  }\n\n  public static BTraceRuntime.Impl getRuntime(\n      String className, ArgsMap args, CommandListener cmdListener, Instrumentation inst) {\n    return FACTORY != null ? FACTORY.getRuntime(className, args, cmdListener, inst) : null;\n  }\n\n  /**\n   * Drop a runtime previously registered via {@link #getRuntime(String, ArgsMap,\n   * CommandListener, java.lang.instrument.Instrumentation)}.\n   *\n   * <p>This releases the internal registry's strong reference to the {@link\n   * BTraceRuntime.Impl} so its class, defining loader, and cached method handles can be\n   * collected. Required for any caller that creates a runtime and then aborts before\n   * attaching it through the normal lifecycle; without it the registry leaks one entry\n   * per aborted attach.\n   */\n  public static void removeRuntime(String className) {\n    BTraceRuntimeAccessImpl.removeRuntime(className);\n  }\n\n  /**\n   * Get the current instrumentation level for the active BTrace probe.\n   * Used by MethodHandle-based level guards to query the level at handler invocation time.\n   * Returns 0 if no runtime is active.\n   */\n  public static int getCurrentLevel() {\n    BTraceRuntimeImplBase current = BTraceRuntimeAccessImpl.getCurrent();\n    if (current != null) {\n      return current.getInstrumentationLevel();\n    }\n    return 0;\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/CommandQueue.java",
    "content": "package org.openjdk.btrace.runtime;\n\nimport org.jctools.queues.MessagePassingQueue;\nimport org.jctools.queues.MpscChunkedArrayQueue;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.MessageCommand;\n\nimport java.util.Collection;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.locks.LockSupport;\n\nfinal class CommandQueue {\n    private static final long DROP_TIMEOUT_MS = Long.getLong(\"org.openjdk.btrace.runtime.cmd.dropTimeoutMillis\", 1L);\n    private static final int BACKOFF_YIELD_ITERS = Integer.getInteger(\"org.openjdk.btrace.runtime.cmd.backoffYieldIters\", 3000);\n    private static final int BACKOFF_SLEEP_ITERS = Integer.getInteger(\"org.openjdk.btrace.runtime.cmd.backoffSleepIters\", 100);\n    private final MpscChunkedArrayQueue<Command> queue;\n    private final AtomicLong droppedCommands = new AtomicLong();\n\n    CommandQueue(int capacity) {\n        queue = new MpscChunkedArrayQueue<>(capacity);\n    }\n\n    public boolean addAll(Collection<? extends Command> c) {\n        boolean rslt = true;\n        for (Command cmd : c) {\n            if (!enqueue(cmd)) {\n                rslt &= false;\n            }\n        }\n        return rslt;\n    }\n\n    public void drain(MessagePassingQueue.Consumer<Command> c, MessagePassingQueue.WaitStrategy wait, MessagePassingQueue.ExitCondition exit) {\n        queue.drain(e -> {\n            long dropped = droppedCommands.get();\n            if (dropped > 0) {\n                c.accept(new MessageCommand(\"Dropped \" + dropped + \" commands\"));\n                droppedCommands.addAndGet(-dropped);\n            }\n            c.accept(e);\n        }, wait, exit);\n    }\n\n    public boolean enqueue(Command cmd) {\n        int backoffCntr = 0;\n        long tsCutOff = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(DROP_TIMEOUT_MS);\n        while (!Thread.interrupted() && !queue.relaxedOffer(cmd)) {\n            if (backoffCntr < BACKOFF_YIELD_ITERS) {\n                Thread.yield();\n            } else if (backoffCntr < BACKOFF_YIELD_ITERS + BACKOFF_SLEEP_ITERS) {\n                LockSupport.parkNanos(1_000_000);\n            }\n            backoffCntr++;\n            if (System.nanoTime() > tsCutOff) {\n                droppedCommands.incrementAndGet();\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public void clear() {\n        queue.clear();\n        droppedCommands.set(0);\n    }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/DOTWriter.java",
    "content": "/*\n * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.runtime;\n\nimport java.io.FileOutputStream;\nimport java.io.PrintStream;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.nio.charset.StandardCharsets;\nimport java.text.CharacterIterator;\nimport java.text.StringCharacterIterator;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.IdentityHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Pattern;\n\n/**\n * Library for constructing a dot file format file containing the state of select objects in the\n * current running application. <br>\n * Introduction ============ <br>\n * Sometimes when debugging an complex problem, a picture is worth more than a thousand words.\n * Looking at an object set graphically can simplify understanding of some of the problems. <br>\n * DOTWriter is designed to analyze a set of Java objects and generate a dot format file. The file\n * can be passed to any number of tools for further analysis. The multi-platform tools are described\n * at http://graphviz.org/. The most commonly used are the 'dot' command and the 'Graphviz'\n * application. <br>\n * The 'dot' command can be used to convert a dot format file into any number of visual format\n * files; jpg, png, pdf et cetera. <br>\n * Ex. dot -Tpdf -osample.pdf sample.dot <br>\n * There are also other tools to convert dot format files to other representations such gxl (using\n * dot2gxl.) <br>\n * Using DOTWriter is straight forward. Simply construct an DOTWriter instance, add objects to\n * observe, then close the instance. <br>\n * Ex. <br>\n * import DOTWriter; <br>\n * var dot = new DOTWriter(\"sample.dot\"); dot.addNodes(a, b, c); dot.close(); <br>\n * There is also a quick and dirty form to do the same. Note: to get dependency edges you need to\n * build the class file with -XDannobindees <br>\n * Ex. DOTWriter.graph(\"sample.dot\", a, b, c); <br>\n * The other calls on the public interface allows more detailed control of the graph. Details below.\n * <br>\n * You also have the ability to control dot format properties. <br>\n * Ex. DOTWriter.graph(\"sample.dot\", \"fillcolor=lightblue\", a, \"fillcolor=lightpink\", b, c); <br>\n * Will display 'a' in blue and 'b'/'c' in pink. Properties are specified in \"k=v, ..., k=v\" form.\n * <br>\n * <br>\n * Public Interface ================ <br>\n * Graphing -------- <br>\n * public DOTWriter(String fileName); <br>\n * The constructor creates a file stream for the dot output. The filename string is the name of the\n * file, and should have the .dot extension. <br>\n * <br>\n * public void close(); <br>\n * This method writes the graph to the file stream and closes out the graph. Any further operations\n * will be ignored. <br>\n * <br>\n * public static void graph(String fileName, Object... objects); <br>\n * All-in-one graph objects. Specify which objects you want graphed. If an object argument is a\n * String then it is used as the default properties for all object arguments following. <br>\n * <br>\n * public void addNodes(Object... objects); <br>\n * Add a set of objects to the graph. If an object argument is a string then the string is used as a\n * property string for the remaining object arguments. <br>\n * <br>\n * public void addNode(String propertyString, Object object); <br>\n * Add an individual object to the graph. The property string defines the dot Properties for the\n * string. If the object is of primitive data type or null then it will be ignored. <br>\n * <br>\n * public void addEdge(Object head, Object tail); public void addEdge(Object head, Object tail,\n * String propertyString); public void addEdge(Object head, int headFieldId, Object tail, int\n * tailFieldId); public void addEdge(Object head, int headFieldId, Object tail, int tailFieldId,\n * String propertyString); <br>\n * Add Edges to the node. Field ids indicate which slot to start/end from, -1 indicates the whole\n * object. <br>\n * <br>\n * <br>\n * Control Display ---------------- <br>\n * public void objectLimit(int objectLimit); <br>\n * The maximum number of objects to display in detail in the graph (default=256.) More objects may\n * be displayed but they will be truncated. Having a lower limit speeds up the processing of the\n * graph. <br>\n * <br>\n * public void fieldLimit(int fieldLimit); <br>\n * The maximum number of fields to display for an object (default=64.) Having a lower limit speeds\n * up the processing of the graph. <br>\n * <br>\n * public void arrayLimit(int arrayLimit); <br>\n * The maximum number of slots to display for an array (default=32.) Having a lower limit speeds up\n * the processing of the graph. <br>\n * <br>\n * public void stringLimit(int stringLimit); <br>\n * The maximum length of a string to display (default=32.) Having a lower limit speeds up the\n * processing of the graph. <br>\n * <br>\n * public void expandCollections(boolean expandCollections); <br>\n * Controls the display of collections. By default, collections are displayed as simple arrays.\n * expandCollections == true, displays collections as individual java objects. <br>\n * public void displayStatics(boolean displayStatics) <br>\n * Controls whether static fields are displayed. By default displayStatics == false. <br>\n * <br>\n * public void displayLinks(boolean displayLinks); <br>\n * Controls whether data links are displayed. By default displayLinks == true. You may want to set\n * displayLinks = false, if all you want to look at is dependencies. <br>\n * Filtering --------- <br>\n * public void includeObjects(Object... objects); <br>\n * Only objects specified are included in the graph. <br>\n * <br>\n * public void excludeObjects(Object... objects) <br>\n * Objects specified are excluded from the graph. This may truncated data links as well. <br>\n * <br>\n * public void includeClasses(Class... clazzes); <br>\n * Only objects that are instances of the specified classes are included in the graph. <br>\n * public void excludeClasses(Class... clazzes); <br>\n * Classes to be excluded from the graph.\n *\n * @author Jim Laskey\n */\npublic class DOTWriter {\n  public static final String DOTWRITER_PREFIX = \"dotwriter.\";\n  // Property settings for fonts.\n  static final String FONTDEFAULTS = \"fontname=Helvetica, fontcolor=black, fontsize=10\";\n  // Default property settings for entire graph.\n  static final String GRAPHDEFAULTS = FONTDEFAULTS + \", rankdir=LR\";\n  // Default property settings for nodes.\n  static final String NODEDEFAULTS =\n      FONTDEFAULTS\n          + \", label=\\\"\\\\N\\\", shape=record, style=filled, fillcolor=lightgrey, color=black\";\n  // Default property settings for edges.\n  static final String EDGEDEFAULTS = FONTDEFAULTS + \", arrowhead=open\";\n  // Style of starting node.\n  static final String STARTNODESTYLE = \"fillcolor=pink\";\n  // Style of intra dependency edge.\n  static final String INTRAEDGESTYLE = \"style=dashed, color=grey\";\n  // Style of inter dependency edge.\n  static final String INTEREDGESTYLE = \"style=dashed, color=darkGrey\";\n  private final DotWriterFormatter dotWriterFormatter = new DotWriterFormatter();\n  // Cache of field information.\n  final Map<Class<?>, Field[]> fieldCache = new HashMap<>();\n  // Maximum number of objects displayed.\n  private int objectLimit = 256;\n  // Maximum number of field entries displayed.\n  private int fieldLimit = 64;\n  // Maximum number of array entries displayed.\n  private int arrayLimit = 32;\n  // Map of visited objects.\n  private final Map<Object, Node> visited = new IdentityHashMap<>();\n  // Graph properties.\n  private final Properties graphProperties = new Properties();\n  // Default node properties.\n  private final Properties nodeProperties = new Properties();\n  // Default edge properties.\n  private final Properties edgeProperties = new Properties();\n  // List of nodes.\n  private final List<Node> nodes = new ArrayList<>();\n  // List of edges.\n  private final List<Edge> edges = new ArrayList<>();\n  // Output stream.\n  private PrintStream dotStream;\n  // True if filters are active.\n  private boolean filtering = false;\n  // Include set of instances.\n  private final Set<Object> includeObjects = new HashSet<>();\n  // Exclude set of instances.\n  private final Set<Object> excludeObjects = new HashSet<>();\n  // Include List of classes.\n  private final List<Class<?>> includeClasses = new ArrayList<>();\n  // Include classes which matching name pattern\n  private Pattern includeClassNames;\n  // Exclude List of classes.\n  private final List<Class<?>> excludeClasses = new ArrayList<>();\n  // Excluse classes with matching name pattern\n  private Pattern excludeClassNames;\n  // True if collections should be expanded.\n  private boolean expandCollections = false;\n  // True if static fields should be displayed.\n  private boolean displayStatics = false;\n  // True if object links should be shown.\n  private boolean displayLinks = true;\n\n  public DOTWriter(String fileName) {\n    try {\n      dotStream = new PrintStream(new FileOutputStream(fileName), true, StandardCharsets.UTF_8.name());\n    } catch (Throwable ignored) {\n    }\n\n    // Set up default properties.\n    graphProperties.addProperties(GRAPHDEFAULTS);\n    nodeProperties.addProperties(NODEDEFAULTS);\n    edgeProperties.addProperties(EDGEDEFAULTS);\n  }\n\n  // All-in-one graph objects.  Specify which objects you want graphed.\n  // If an object is a String then it is used as the default properties\n  // for all objects following.\n  public static void graph(String fileName, Object... objects) {\n    // Open the dot file.\n    DOTWriter writer = new DOTWriter(fileName);\n    // Hilight starting nodes in pink.\n    String propertyString = STARTNODESTYLE;\n\n    // For each argument.\n    for (Object object : objects) {\n      // If string the swap default properties.\n      if (object instanceof String) {\n        propertyString = (String) object;\n      } else {\n        writer.addNode(propertyString, object);\n      }\n    }\n\n    // Dump and close out the dot file.\n    writer.close();\n  }\n\n  // Escape a quoted value string for output.\n  private static String escapeString(String value) {\n    if (needsEscape(value)) {\n      StringBuilder result = new StringBuilder();\n      result.append('\\\"');\n      StringCharacterIterator iterator = new StringCharacterIterator(value);\n\n      for (char ch = iterator.current(); ch != CharacterIterator.DONE; ch = iterator.next()) {\n        if (ch == '\\\"' || ch == '\\'' || ch == '{' || ch == '}' || ch == '[' || ch == ']') {\n          result.append('\\\\');\n          result.append(ch);\n        } else if (ch < ' ' || ch > '~') {\n          result.append(\"\\\\\\\\u\");\n          String hex = \"0000\" + Integer.toHexString(ch);\n          hex = hex.substring(hex.length() - 4);\n          result.append(hex);\n        } else {\n          result.append(ch);\n        }\n      }\n\n      result.append('\\\"');\n      value = result.toString();\n    }\n\n    return value;\n  }\n\n  // Return true if the string needs to be quoted.\n  private static boolean needsEscape(String value) {\n    if (value.length() > 0 && value.charAt(0) == '\\\"') return false;\n\n    StringCharacterIterator iterator = new StringCharacterIterator(value);\n\n    for (char ch = iterator.current(); ch != CharacterIterator.DONE; ch = iterator.next()) {\n      if (!Character.isJavaIdentifierPart(ch) && ch != '-') {\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  public void customize(java.util.Properties props) {\n    String prop = props.getProperty(DOTWRITER_PREFIX + \"objectlimit\");\n    if (prop != null) {\n      objectLimit(Integer.parseInt(prop));\n    }\n    prop = props.getProperty(DOTWRITER_PREFIX + \"fieldLimit\");\n    if (prop != null) {\n      fieldLimit(Integer.parseInt(prop));\n    }\n    prop = props.getProperty(DOTWRITER_PREFIX + \"stringLimit\");\n    if (prop != null) {\n      dotWriterFormatter.stringLimit(Integer.parseInt(prop));\n    }\n    prop = props.getProperty(DOTWRITER_PREFIX + \"arrayLimit\");\n    if (prop != null) {\n      arrayLimit(Integer.parseInt(prop));\n    }\n    prop = props.getProperty(DOTWRITER_PREFIX + \"expandCollections\");\n    if (prop != null) {\n      expandCollections(Boolean.parseBoolean(prop));\n    }\n    // accept both the correct property and the legacy misspelling for compatibility\n    prop = props.getProperty(DOTWRITER_PREFIX + \"displayLinks\");\n    if (prop == null) {\n      prop = props.getProperty(DOTWRITER_PREFIX + \"diaplayLinks\");\n    }\n    if (prop != null) {\n      displayLinks(Boolean.parseBoolean(prop));\n    }\n    prop = props.getProperty(DOTWRITER_PREFIX + \"displayStatics\");\n    if (prop != null) {\n      displayStatics(Boolean.parseBoolean(prop));\n    }\n    prop = props.getProperty(DOTWRITER_PREFIX + \"excludeClassNames\");\n    if (prop != null) {\n      excludeClassNames(Pattern.compile(prop));\n    }\n    prop = props.getProperty(DOTWRITER_PREFIX + \"includeClassNames\");\n    if (prop != null) {\n      includeClassNames(Pattern.compile(prop));\n    }\n  }\n\n  // Add a set of nodes to the graph.  If the object is a string then the string\n  // is used as a property string for the remaining objects.\n  public void addNodes(Object... objects) {\n    String propertyString = null;\n\n    for (Object object : objects) {\n      if (object instanceof String) {\n        propertyString = (String) object;\n      } else {\n        addNode(propertyString, object);\n      }\n    }\n  }\n\n  // Add an object to the graph.\n  public void addNode(String propertyString, Object object) {\n    // No nulls in the graph.\n    if (object == null) return;\n    // No primitive types in the graph.\n    if (isPrimitive(object)) return;\n\n    // Capture where to continue graphing.\n    int index = nodes.size();\n    // Add the new node or get the existing one.\n    Node newNode = getNode(object);\n\n    // While the node list is not exhausted.\n    for (; index < nodes.size(); index++) {\n      // get the next node.\n      Node node = nodes.get(index);\n      // Get the node object.\n      object = node.object;\n      // Get the object class.\n      Class clazz = object.getClass();\n      // Add object header to label.\n      addHeader(object, clazz, node);\n\n      // If the object is an array.\n      if (clazz.isArray()) {\n        // Display detail if under object limit and not excluded.\n        if (index < arrayLimit && shouldDetail(object)) {\n          addArrayDetail(object, node);\n        } else {\n          // Indicate there is more than displayed.\n          addContinuation(node);\n        }\n      } else {\n        // Display detail if under object limit and not excluded.\n        if (index < objectLimit && shouldDetail(object)) {\n          if (!expandCollections && object instanceof Collection) {\n            // Display collection as an array of enties.\n            addCollectionDetail(object, clazz, node);\n          } else if (!expandCollections && object instanceof Map) {\n            // Display map as an array of key->value.\n            addMapDetail(object, clazz, node);\n          } else if (displayStatics && object instanceof Class) {\n            // Display class static fields.\n            addClassDetail(object, clazz, node);\n          } else {\n            // Display as a detailed java object.\n            addObjectDetail(object, clazz, node);\n          }\n        } else {\n          // Indicate there is more than displayed.\n          addContinuation(node);\n        }\n      }\n    }\n\n    // Add properties to the node if present.\n    if (propertyString != null) {\n      newNode.addProperties(propertyString);\n    }\n  }\n\n  // Set maximum number of objects displayed in detail.\n  public void objectLimit(int objectLimit) {\n    this.objectLimit = objectLimit;\n  }\n\n  // Set maximum number of field entries displayed.\n  public void fieldLimit(int fieldLimit) {\n    this.fieldLimit = fieldLimit;\n  }\n\n  // Set maximum number of array entries displayed.\n  public void arrayLimit(int arrayLimit) {\n    this.arrayLimit = arrayLimit;\n  }\n\n  // Set maximum number of string characters displayed\n  public void stringLimit(int stringLimit) {\n    dotWriterFormatter.stringLimit(stringLimit);\n  }\n\n  // Control the switching of collections from detail to expanded.\n  public void expandCollections(boolean expandCollections) {\n    this.expandCollections = expandCollections;\n  }\n\n  // Control whether static fields should be shown.\n  public void displayStatics(boolean displayStatics) {\n    this.displayStatics = displayStatics;\n  }\n\n  // Control whether object links should be shown.\n  public void displayLinks(boolean displayLinks) {\n    this.displayLinks = displayLinks;\n  }\n\n  // Add objects to the include list.\n  public void includeObjects(Object... objects) {\n    includeObjects.addAll(Arrays.asList(objects));\n    filtering = true;\n  }\n\n  // Add objects to the exclude list.\n  public void excludeObjects(Object... objects) {\n    excludeObjects.addAll(Arrays.asList(objects));\n    filtering = true;\n  }\n\n  // Add classes to the include list.\n  public void includeClasses(Class<?>... clazzes) {\n    includeClasses.addAll(Arrays.asList(clazzes));\n    filtering = true;\n  }\n\n  public void includeClassNames(Pattern pattern) {\n    includeClassNames = pattern;\n    filtering = true;\n  }\n\n  // Adds classes to the exclude list.\n  public void excludeClasses(Class<?>... clazzes) {\n    excludeClasses.addAll(Arrays.asList(clazzes));\n    filtering = true;\n  }\n\n  public void excludeClassNames(Pattern pattern) {\n    excludeClassNames = pattern;\n    filtering = true;\n  }\n\n  // This method adds a new edge to the graph.\n  public void addEdge(Object head, Object tail) {\n    addEdge(head, -1, tail, -1, null);\n  }\n\n  public void addEdge(Object head, Object tail, String propertyString) {\n    addEdge(head, -1, tail, -1, propertyString);\n  }\n\n  public void addEdge(Object head, int headFieldId, Object tail, int tailFieldId) {\n    addEdge(head, headFieldId, tail, tailFieldId, null);\n  }\n\n  public void addEdge(\n      Object head, int headFieldId, Object tail, int tailFieldId, String propertyString) {\n    addEdge(getNode(head), headFieldId, getNode(tail), tailFieldId, propertyString);\n  }\n\n  private void addEdge(Node head, int headFieldId, Node tail, int tailFieldId) {\n    addEdge(head, headFieldId, tail, tailFieldId, null);\n  }\n\n  // Write the graph and close the dot file.\n  public void close() {\n    if (dotStream != null) {\n      writeGraph();\n      dotStream.close();\n      dotStream = null;\n    }\n  }\n\n  // Return true if the object is a primitive type.\n  private boolean isPrimitive(Object object) {\n    return object.getClass().isPrimitive()\n        || object instanceof Number\n        || object instanceof Boolean\n        || object instanceof String;\n  }\n\n  // Write the graph to the stream.\n  private void writeGraph() {\n    dotStream.println(\"digraph g {\");\n\n    dotStream.print(\" graph \");\n    graphProperties.writeProperties(dotStream);\n    dotStream.println(\";\");\n\n    dotStream.print(\" node \");\n    nodeProperties.writeProperties(dotStream);\n    dotStream.println(\";\");\n\n    dotStream.print(\" edge \");\n    edgeProperties.writeProperties(dotStream);\n    dotStream.println(\";\");\n\n    for (Node node : nodes) {\n      dotStream.print(\" node\" + node.id + \" \");\n      node.writeProperties(dotStream);\n      dotStream.println(\";\");\n    }\n\n    for (Edge edge : edges) {\n      dotStream.print(\n          \" node\" + edge.head.id + (edge.headFieldId < 0 ? \":f\" : \":f\" + edge.headFieldId));\n      dotStream.print(\" -> \");\n      dotStream.print(\n          \" node\" + edge.tail.id + (edge.tailFieldId < 0 ? \":f\" : \":f\" + edge.tailFieldId));\n      dotStream.print(\" \");\n      edge.writeProperties(dotStream);\n      dotStream.println(\";\");\n    }\n\n    dotStream.println(\"}\");\n  }\n\n  // Add an object to the node work list.\n  private Node getNode(Object object) {\n    // Don't add nulls to graph.\n    if (object == null) return null;\n\n    // Some object types fail mapping.\n    Node node = null;\n    try {\n      node = visited.get(object);\n    } catch (Throwable ex) {\n      return null;\n    }\n\n    // If the node is not found add one.\n    if (node == null) {\n      node = new Node(nodes.size(), object);\n      nodes.add(node);\n      visited.put(object, node);\n    }\n\n    return node;\n  }\n\n  //\n  // Private interface.\n  //\n\n  // Determine if a node should be detailed based on object and class filters.\n  private boolean shouldDetail(Object object) {\n    if (object == this) return false;\n    if (!filtering) return true;\n\n    if (!includeObjects.isEmpty()) {\n      return includeObjects.contains(object);\n    }\n\n    if (!includeClasses.isEmpty()) {\n      for (Class<?> clazz : includeClasses) {\n        if (clazz.isInstance(object)) return true;\n      }\n\n      return false;\n    }\n\n    if (includeClassNames != null) {\n      return includeClassNames.matcher(object.getClass().getName()).matches();\n    }\n\n    if (!excludeObjects.isEmpty()) {\n      if (excludeObjects.contains(object)) return false;\n    }\n\n    if (!excludeClasses.isEmpty()) {\n      for (Class<?> clazz : excludeClasses) {\n        if (clazz.isInstance(object)) return false;\n      }\n    }\n\n    if (excludeClassNames != null) {\n      return !excludeClassNames.matcher(object.getClass().getName()).matches();\n    }\n    return true;\n  }\n\n  // Add a new edge to the graph.\n  private void addEdge(\n      Node head, int headFieldId, Node tail, int tailFieldId, String propertyString) {\n    // Exclude null nodes.\n    if (head == null || tail == null) return;\n    // Exclude edges to nodes that disn't get displayed.\n    if (headFieldId > getLimit(head) && head.id >= objectLimit) headFieldId = -1;\n    if (tailFieldId > getLimit(tail) && tail.id >= objectLimit) tailFieldId = -1;\n\n    // Create edge.\n    Edge edge = new Edge(edges.size(), head, headFieldId, tail, tailFieldId);\n    // Add properties if present.\n    if (propertyString != null) edge.addProperties(propertyString);\n    // Add to edge list.\n    edges.add(edge);\n  }\n\n  // Return the field/slot limit for a node's object.\n  private int getLimit(Node node) {\n    return node.object.getClass().isArray() ? arrayLimit : fieldLimit;\n  }\n\n  // Return a displayable name for the specified class.\n  private String getClassName(Class clazz) {\n    String name = clazz.getCanonicalName();\n    if (name == null) name = clazz.getName();\n    if (name == null) name = clazz.getSimpleName();\n    return name;\n  }\n\n  // Add the header information about the object.\n  private void addHeader(Object object, Class clazz, Node node) {\n    // Use object if displaying statics.\n    if (displayStatics && object instanceof Class) clazz = (Class) object;\n    // Use name as title.\n    String className = getClassName(clazz);\n\n    if (object instanceof Class) {\n      // Flag Class objects.\n      className += \"(Class)\";\n    }\n\n    // Start label for node.\n    node.addProperty(\"label\", \"<f> \" + className);\n  }\n\n  // Indicate that the object has more fields.\n  private void addContinuation(Node node) {\n    node.extendProperty(\"label\", \" | ...\");\n  }\n\n  // Return the value of a field.\n  private Object getValue(Field field, Object object) {\n    Object value = null;\n\n    try {\n      value = field.get(object);\n    } catch (Throwable ignored) {\n    }\n\n    return value;\n  }\n\n  // Return an array of all the fields in a given class.\n  private Field[] getFields(Class clazz) {\n    if (clazz == null) return new Field[0];\n    if (displayStatics && clazz == Class.class) return new Field[0];\n\n    Field[] fields = fieldCache.get(clazz);\n    if (fields != null) return fields;\n\n    Field[] superFields = getFields(clazz.getSuperclass());\n    Field[] classFields = clazz.getDeclaredFields();\n\n    fields = new Field[superFields.length + classFields.length];\n    System.arraycopy(superFields, 0, fields, 0, superFields.length);\n    System.arraycopy(classFields, 0, fields, superFields.length, classFields.length);\n\n    fieldCache.put(clazz, fields);\n\n    return fields;\n  }\n\n  // Add the detail information about the object.\n  private void addObjectDetail(Object object, Class clazz, Node node) {\n    Field[] fields = getFields(clazz);\n\n    if (displayStatics && fields.length != 0) {\n      addEdge(node, -1, getNode(clazz), -1);\n    }\n\n    for (int index = 0; index < fields.length && index < fieldLimit; index++) {\n      Field field = fields[index];\n      // Ignore static fields.\n      if ((field.getModifiers() & Modifier.STATIC) != 0) continue;\n\n      // Add record row for field.\n      field.setAccessible(true);\n      String name = field.getName();\n      Object value = getValue(field, object);\n      Format format = new Format(value);\n      addNodeField(node, name, index, format.string);\n\n      // If linking to another object then add edge.\n      if (displayLinks && !format.isSimple) {\n        addEdge(node, index, getNode(value), -1);\n      }\n    }\n\n    // Indicate if object is too big to display.\n    if (fields.length >= fieldLimit) {\n      addContinuation(node);\n    }\n  }\n\n  // Add the detail information about a class.\n  private void addClassDetail(Object object, Class clazz, Node node) {\n    Field[] fields = getFields((Class) object);\n\n    for (int index = 0; index < fields.length && index < fieldLimit; index++) {\n      Field field = fields[index];\n      // Only look at static fields.\n      if ((field.getModifiers() & Modifier.STATIC) == 0) continue;\n\n      // Add record row for field.\n      field.setAccessible(true);\n      String name = field.getName();\n      Object value = getValue(field, object);\n      Format format = new Format(value);\n      addNodeField(node, name, index, format.string);\n\n      // If linking to another object then add edge.\n      if (displayLinks && !format.isSimple) {\n        addEdge(node, index, getNode(value), -1);\n      }\n    }\n\n    // Indicate if object is too big to display.\n    if (fields.length >= fieldLimit) {\n      addContinuation(node);\n    }\n  }\n\n  // Add the detail information about a collection.\n  private void addCollectionDetail(Object object, Class clazz, Node node) {\n    // Convert colection to array and display as array.\n    Object[] array = ((Collection) object).toArray();\n    addArrayDetail(array, node);\n  }\n\n  // Add the detail information about a map.\n  private void addMapDetail(Object object, Class clazz, Node node) {\n    // Convert map to array and display as array.\n    Object[] array = ((Map) object).entrySet().toArray();\n    addArrayDetail(array, node);\n  }\n\n  // Add the detail information about the array.\n  private void addArrayDetail(Object object, Node node) {\n    int length = Array.getLength(object);\n\n    if (object instanceof char[] || (object instanceof byte[] && allASCII((byte[]) object))) {\n      // If char or displayable byte array then display as string.\n      Format format = new Format(object);\n      String string = \" | \" + format.string;\n      node.extendProperty(\"label\", string);\n      length = 0;\n    } else {\n      // One line of record per slot in array.\n      for (int index = 0; index < length && index < arrayLimit; index++) {\n        // Add record row for slot.\n        Object value = Array.get(object, index);\n        Format format = new Format(value);\n        addNodeField(node, null, index, format.string);\n\n        // If linking to another object then add edge.\n        if (displayLinks && !format.isSimple) {\n          addEdge(node, index, getNode(value), -1);\n        }\n      }\n    }\n\n    // Indicate if object is too big to display.\n    if (length >= arrayLimit) {\n      addContinuation(node);\n    }\n  }\n\n  // Add a field to a node.\n  private void addNodeField(Node node, String fieldName, int fieldId, String valueString) {\n    // Start record row.\n    String labelString = \" | \";\n    // Add report port for edges.\n    labelString += \"<f\" + fieldId + \"> \";\n    // Add field name.\n    if (fieldName != null) labelString += fieldName + \": \";\n    // Add value.\n    labelString += valueString;\n    // Add to record description.\n    node.extendProperty(\"label\", labelString);\n  }\n\n  // Return true if all the characters in the array are ASCII characters.\n  private boolean allASCII(byte[] array) {\n    for (byte b : array) {\n      char ch = (char) b;\n      if (ch < ' ' || '~' < ch) return false;\n    }\n\n    return true;\n  }\n\n  // This class maintains properties.\n  static class Properties {\n    // Property map.\n    private final Map<String, String> properties = new HashMap<>();\n\n    // Adds a new property to the map.\n    void addProperty(String key, String value) {\n      properties.put(key, value);\n    }\n\n    // Adds new properties from a \"key=value, key=value\" string.\n    void addProperties(String propertyString) {\n      // Split on the commas.\n      String[] kvs = propertyString.split(\"\\\\s*,\\\\s*\");\n\n      // For each key=value pair.\n      for (String kv : kvs) {\n        // Split on the equals.\n        String[] pair = kv.split(\"\\\\s*=\\\\s*\");\n\n        // If no equals.\n        if (pair.length == 1) {\n          properties.put(pair[0], \"true\");\n        } else {\n          properties.put(pair[0], pair[1]);\n        }\n      }\n    }\n\n    // Adds new information to a property.\n    void extendProperty(String key, String extension) {\n      // Get existing property\n      String value = getProperty(key);\n      // If no property exists then start one.\n      if (value == null) value = \"\";\n      // Add the extension to the value.\n      value += extension;\n      // Update the property.\n      addProperty(key, value);\n    }\n\n    // Return the value of the property, null if not found.\n    String getProperty(String key) {\n      return properties.get(key);\n    }\n\n    // Write properties to a stream in the form \"[key=value, ..., key=value]\".\n    void writeProperties(PrintStream dotStream) {\n      // Only if there are properties.\n      if (!properties.isEmpty()) {\n        dotStream.print(\"[\");\n\n        String comma = \"\";\n        for (String key : properties.keySet()) {\n          String value = properties.get(key);\n\n          // true properties don't require a value.\n          if (value.equals(\"true\")) {\n            dotStream.print(comma + key);\n          } else {\n            dotStream.print(comma + key + \"=\" + escapeString(value));\n          }\n\n          comma = \", \";\n        }\n\n        dotStream.print(\"]\");\n      }\n    }\n  }\n\n  // This class maintains information about a graph element.\n  static class Element extends Properties {\n    // Identifying number.\n    final int id;\n\n    Element(int id) {\n      this.id = id;\n    }\n  }\n\n  // This class maintains information about a node.\n  static class Node extends Element {\n    // Subject of the node.\n    final Object object;\n\n    Node(int id, Object object) {\n      super(id);\n      this.object = object;\n    }\n  }\n\n  // This class maintains information about an edge.\n  static class Edge extends Element {\n    // Beginning and end of edge.\n    final Node head;\n    final int headFieldId;\n    final Node tail;\n    final int tailFieldId;\n\n    Edge(int id, Node head, int headFieldId, Node tail, int tailFieldId) {\n      super(id);\n      this.head = head;\n      this.headFieldId = headFieldId;\n      this.tail = tail;\n      this.tailFieldId = tailFieldId;\n    }\n  }\n\n  // This class makes simplifies the display of values.\n  class Format {\n    // String representation of value.\n    String string = \"\";\n\n    // True if the value is simple and can't be referenced externally.\n    boolean isSimple = true;\n\n    Format(Object value) {\n      if (value == null) {\n        // nulls as is, but may be referenced .\n        string += value;\n        isSimple = false;\n      } else if (value instanceof String) {\n        // Strings in double quotes.\n        string = dotWriterFormatter.formatString((String) value, \"\\\"\");\n      } else if (value instanceof char[]) {\n        // char arrays as single quote strings.\n        string = dotWriterFormatter.formatString(new String((char[]) value), \"'\");\n      } else if (value instanceof byte[] && allASCII((byte[]) value)) {\n        // byte arrays of ascii characters as single quote strings.\n        string =\n            dotWriterFormatter.formatString(\n                new String((byte[]) value, StandardCharsets.UTF_8), \"'\");\n      } else if (value instanceof Character) {\n        // Quote characters.\n        Character character = (Character) value;\n        string = \"'\" + character + \"'\";\n      } else if (!expandCollections && value instanceof Map.Entry) {\n        // Map entries as key->value.\n        Map.Entry entry = (Map.Entry) value;\n        Format keyFormat = new Format(entry.getKey());\n        Format valueFormat = new Format(entry.getValue());\n        if (!keyFormat.isSimple) {\n          isSimple = false;\n        } else {\n          string = keyFormat.string + \"-\\\\>\";\n\n          if (valueFormat.isSimple) {\n            string += valueFormat.string;\n          } else {\n            isSimple = false;\n          }\n        }\n      } else if (isPrimitive(value)) {\n        // Primitive types as is.\n        string += value;\n      } else {\n        // Reference to another object.\n        isSimple = false;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/DotWriterFormatter.java",
    "content": "package org.openjdk.btrace.runtime;\n\nclass DotWriterFormatter {\n  // Maximum number of string characters displayed.\n  private int stringLimit = 32;\n\n  DotWriterFormatter() {}\n\n  // Set maximum number of string characters displayed.\n  void stringLimit(int stringLimit) {\n    this.stringLimit = stringLimit;\n  }\n\n  // Formats a string value, truncating if needed.\n  String formatString(String string, String quote) {\n    boolean isLong = string.length() > stringLimit;\n    if (isLong) string = string.substring(0, stringLimit - 1);\n    string = quote + string + quote;\n    if (isLong) string += \"...\";\n    return string;\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/ExitException.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.runtime;\n\n/**\n * Instance of this exception is thrown to implement BTrace exit built-in function.\n *\n * @author A. Sundararajan\n */\npublic final class ExitException extends RuntimeException {\n  private final int exitCode;\n\n  ExitException(int code) {\n    exitCode = code;\n  }\n\n  int exitCode() {\n    return exitCode;\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/ExtensionContextImpl.java",
    "content": "package org.openjdk.btrace.runtime;\n\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.extensions.Extension;\nimport org.openjdk.btrace.core.extensions.ExtensionContext;\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.core.extensions.PermissionSet;\n\n/**\n * Implementation of {@link ExtensionContext} backed by a {@link BTraceRuntimeImplBase}.\n *\n * <p>Provides extensions with access to the BTrace runtime services for their associated script.\n */\npublic final class ExtensionContextImpl implements ExtensionContext {\n  private final BTraceRuntimeImplBase runtime;\n  private final String scriptClassName;\n  private final PermissionSet permissions;\n\n  /**\n   * Creates a new extension context.\n   *\n   * @param runtime the BTrace runtime instance\n   * @param scriptClassName the script class name\n   * @param permissions the granted permissions\n   */\n  public ExtensionContextImpl(\n      BTraceRuntimeImplBase runtime, String scriptClassName, PermissionSet permissions) {\n    this.runtime = runtime;\n    this.scriptClassName = scriptClassName;\n    this.permissions = permissions;\n  }\n\n  @Override\n  public void send(String message) {\n    runtime.send(message);\n  }\n\n  @Override\n  public void send(Command command) {\n    runtime.send(command);\n  }\n\n  @Override\n  public ArgsMap getArgs() {\n    return runtime.getArgsMap();\n  }\n\n  @Override\n  public String getScriptClassName() {\n    return scriptClassName;\n  }\n\n  @Override\n  public PermissionSet getPermissions() {\n    return permissions;\n  }\n\n  @Override\n  public boolean hasPermission(Permission permission) {\n    return permissions.has(permission);\n  }\n\n  void registerExtension(Extension ext) {\n    runtime.registerExtension(ext);\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/ExtensionIndy.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.runtime;\n\nimport org.openjdk.btrace.core.SharedSettings;\nimport org.openjdk.btrace.core.annotations.InjectionMode;\nimport org.openjdk.btrace.core.extensions.Extension;\nimport org.openjdk.btrace.core.extensions.ExtensionContext;\nimport org.openjdk.btrace.extension.ExtensionBridge;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.invoke.CallSite;\nimport java.lang.invoke.ConstantCallSite;\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.MethodType;\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\n\n/**\n * Invokedynamic bootstrap methods for BTrace extension access.\n * Provides classloader bridging between BTrace scripts and extensions.\n */\npublic final class ExtensionIndy {\n  private static final Logger logger = LoggerFactory.getLogger(ExtensionIndy.class);\n  /**\n   * Bridge to extension system. Set by ExtensionBridgeImpl during agent initialization.\n   * Must be volatile for visibility across threads.\n   */\n  public static volatile ExtensionBridge bridge = null;\n\n  static {\n    logger.info(\"ExtensionIndy loaded\");\n  }\n\n  /**\n   * Bootstrap method for extension service field access.\n   * Called when a script accesses an @Injected field for the first time.\n   *\n   * @param caller caller's lookup context\n   * @param fieldName field name (for debugging)\n   * @param type method type - should be {@code () -> ServiceInterface}\n   * @param serviceClassName fully qualified service class name\n   * @param serviceType legacy service type (ignored; retained for compatibility)\n   * @param factoryMethod optional factory method name (empty string if none)\n   * @return CallSite that returns the extension service instance\n   */\n  public static CallSite bootstrapFieldGet(\n      MethodHandles.Lookup caller,\n      String fieldName,\n      MethodType type,\n      String serviceClassName,\n      String serviceType,\n      String factoryMethod,\n      Integer optionalFlag,\n      String injectMode)\n      throws Exception {\n    MethodHandle mh;\n    boolean isOptional = optionalFlag != 0;\n    InjectionMode parsedMode = parseInjectionMode(injectMode);\n    InjectionMode effectiveMode = resolveMode(parsedMode);\n    logger.debug(\"linking: mode={}\", effectiveMode);\n\n    boolean linkLog = isLinkLogEnabled();\n    try {\n      Class<?> serviceClass = requireServiceClass(serviceClassName);\n      Object instance = createServiceInstance(serviceClass, factoryMethod, serviceClassName);\n      mh = MethodHandles.constant(type.returnType(), instance);\n      if (linkLog) logger.info(\"Linked service '{}' to '{}'\", serviceClassName, serviceClass.getName());\n\n    } catch (Throwable t) {\n      logger.debug(\"Bootstrap failed for '{}': {}\", serviceClassName, t.toString());\n      // Decide fallback behavior based on optional flag and injection mode.\n      // In SHIM mode we allow shim fallback even for non-optional injections so scripts can run\n      // with no-ops when implementations are blocked by permissions.\n      boolean allowShim = (effectiveMode == InjectionMode.SHIM) || isOptional;\n      if (allowShim) {\n        Object fallback = resolvePreGeneratedShim(type, caller, effectiveMode);\n        if (fallback == null) {\n          fallback = createFallbackInstance(effectiveMode, type, caller, t);\n        }\n        if (linkLog) logger.warn(\"Service '{}' unavailable; using {} fallback\",\n            serviceClassName, (effectiveMode == InjectionMode.SHIM ? \"SHIM\" : \"THROW\"));\n        mh = MethodHandles.constant(type.returnType(), fallback);\n      } else {\n        throw t instanceof Exception ? (Exception) t : new Exception(t);\n      }\n    }\n\n    try {\n      mh = mh.asType(type);\n    } catch (java.lang.invoke.WrongMethodTypeException ignored) {\n    }\n    return new ConstantCallSite(mh);\n  }\n\n  private static Object resolvePreGeneratedShim(MethodType type, MethodHandles.Lookup caller, InjectionMode mode) {\n    try {\n      Class<?> iface = type.returnType();\n      ClassLoader cl = iface.getClassLoader();\n      ShimTarget target = ShimIndex.resolve(iface, cl);\n      if (target == null) return null;\n      String fqcn = (mode == InjectionMode.SHIM ? target.noopFqcn : target.throwFqcn);\n      if (fqcn == null || fqcn.isEmpty()) return null;\n      ClassLoader loader = (cl != null ? cl : ClassLoader.getSystemClassLoader());\n      Class<?> shim = loader.loadClass(fqcn);\n      java.lang.reflect.Field f = shim.getField(\"INSTANCE\");\n      Object inst = f.get(null);\n      if (iface.isInstance(inst)) return inst;\n    } catch (Throwable ignore) {\n    }\n    return null;\n  }\n\n  private static InjectionMode resolveMode(InjectionMode fieldMode) {\n    if (fieldMode != null && fieldMode != InjectionMode.UNSPECIFIED) {\n      return fieldMode;\n    }\n    String prop = System.getProperty(\"btrace.extension.shimMode\", \"throw\");\n    if (\"shim\".equalsIgnoreCase(prop)) return InjectionMode.SHIM;\n    return InjectionMode.THROW;\n  }\n\n  private static InjectionMode parseInjectionMode(String injectMode) {\n    if (injectMode == null || injectMode.isEmpty()) return InjectionMode.UNSPECIFIED;\n    if (\"THROW\".equalsIgnoreCase(injectMode)) return InjectionMode.THROW;\n    if (\"SHIM\".equalsIgnoreCase(injectMode)) return InjectionMode.SHIM;\n    return InjectionMode.UNSPECIFIED;\n  }\n\n  private static boolean isLinkLogEnabled() {\n    return SharedSettings.GLOBAL.isDebug() || Boolean.getBoolean(\"btrace.extension.linkLog\");\n  }\n\n  private static Class<?> requireServiceClass(String serviceClassName) throws Exception {\n    if (bridge == null) {\n      throw new IllegalStateException(\"ExtensionIndy.bridge not initialized\");\n    }\n    Class<?> serviceClass = bridge.getExtensionClass(serviceClassName);\n    if (serviceClass == null) {\n      throw new ClassNotFoundException(\"Extension service not found: \" + serviceClassName);\n    }\n    if (serviceClass.isInterface()) {\n      throw new IllegalStateException(\"No implementation available for service (interface returned): \" + serviceClassName);\n    }\n    logger.debug(\"Resolved service '{}' to '{}'\", serviceClassName, serviceClass.getName());\n    return serviceClass;\n  }\n\n  private static MethodHandle findInstantiationHandle(Class<?> serviceClass, String factoryMethod) throws Exception {\n    MethodHandles.Lookup lookup = MethodHandles.publicLookup();\n    boolean useFactory = factoryMethod != null && !factoryMethod.isEmpty();\n    try {\n      if (useFactory) {\n        return lookup.findStatic(serviceClass, factoryMethod, MethodType.methodType(serviceClass));\n      }\n      return lookup.findConstructor(serviceClass, MethodType.methodType(void.class));\n    } catch (Throwable t) {\n      logger.debug(\"Instantiation handle resolution failed for '{}': {}\", serviceClass.getName(), t.toString());\n      throw new IllegalStateException(\"Unable to create service instance for \" + serviceClass.getName(), t);\n    }\n  }\n\n  private static Object createServiceInstance(\n      Class<?> serviceClass, String factoryMethod, String serviceClassName) throws Exception {\n    MethodHandle mh = findInstantiationHandle(serviceClass, factoryMethod);\n    Object instance;\n    try {\n      instance = mh.invokeWithArguments();\n    } catch (Throwable t) {\n      throw new IllegalStateException(\"Unable to instantiate service \" + serviceClassName, t);\n    }\n    if (instance instanceof Extension) {\n      Extension ext = (Extension) instance;\n      ExtensionContext ctx = BTraceRuntimeAccess.currentContext();\n      if (ctx == null) {\n        throw new IllegalStateException(\"Extension context not available for \" + serviceClassName);\n      }\n      ext.initialize(ctx);\n      tryRegisterExtension(ctx, ext);\n    }\n    return instance;\n  }\n\n  private static void tryRegisterExtension(ExtensionContext ctx, Extension ext) {\n    try {\n      Method m = ctx.getClass().getDeclaredMethod(\"registerExtension\", Extension.class);\n      m.setAccessible(true);\n      m.invoke(ctx, ext);\n    } catch (Throwable ignore) {\n      // best effort; closing will be skipped if registration fails\n    }\n  }\n\n  private static Object createFallbackInstance(\n      InjectionMode mode, MethodType type, MethodHandles.Lookup caller, Throwable cause) throws Exception {\n    Class<?> iface = type.returnType();\n    if (!iface.isInterface()) {\n      return null;\n    }\n    ClassLoader loader = iface.getClassLoader();\n    if (loader == null) {\n      loader = ClassLoader.getSystemClassLoader();\n    }\n    InvocationHandler handler;\n    if (mode == InjectionMode.SHIM) {\n      handler = new NoOpHandler();\n    } else {\n      handler = new ThrowingHandler(iface.getName(), cause);\n    }\n    Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] {iface}, handler);\n    return proxy;\n  }\n\n  private static final class NoOpHandler implements InvocationHandler {\n    @Override\n    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n      String name = method.getName();\n      int paramCount = method.getParameterCount();\n      if (name.equals(\"toString\") && paramCount == 0) return \"NoOp\" + proxy.getClass().getInterfaces()[0].getSimpleName();\n      if (name.equals(\"hashCode\") && paramCount == 0) return System.identityHashCode(proxy);\n      if (name.equals(\"equals\") && paramCount == 1) return proxy == args[0];\n      Class<?> rt = method.getReturnType();\n      if (rt == void.class) return null;\n      if (rt.isPrimitive()) {\n        if (rt == boolean.class) return false;\n        if (rt == byte.class) return (byte) 0;\n        if (rt == short.class) return (short) 0;\n        if (rt == char.class) return (char) 0;\n        if (rt == int.class) return 0;\n        if (rt == long.class) return 0L;\n        if (rt == float.class) return 0f;\n        if (rt == double.class) return 0d;\n      }\n      return null;\n    }\n  }\n\n  private static final class ThrowingHandler implements InvocationHandler {\n    private final String iface;\n    private final Throwable cause;\n\n    ThrowingHandler(String iface, Throwable cause) {\n      this.iface = iface;\n      this.cause = cause;\n    }\n\n    @Override\n    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n      String name = method.getName();\n      int paramCount = method.getParameterCount();\n      if (name.equals(\"toString\") && paramCount == 0) return \"Throwing\" + proxy.getClass().getInterfaces()[0].getSimpleName();\n      if (name.equals(\"hashCode\") && paramCount == 0) return System.identityHashCode(proxy);\n      if (name.equals(\"equals\") && paramCount == 1) return proxy == args[0];\n      IllegalStateException ex = new IllegalStateException(\n          \"BTrace optional service unavailable: \" + iface, cause);\n      throw ex;\n    }\n  }\n\n  private ExtensionIndy() {\n    // Utility class, no instances\n  }\n\n  private static final class ShimTarget {\n    final String noopFqcn;\n    final String throwFqcn;\n\n    ShimTarget(String noopFqcn, String throwFqcn) {\n      this.noopFqcn = noopFqcn;\n      this.throwFqcn = throwFqcn;\n    }\n  }\n\n  private static final class ShimIndex {\n    private static volatile java.util.Map<String, ShimTarget> cache;\n\n    static ShimTarget resolve(Class<?> iface, ClassLoader cl) {\n      String key = iface.getName();\n      java.util.Map<String, ShimTarget> map = cache;\n      if (map == null) {\n        synchronized (ShimIndex.class) {\n          if (cache == null) {\n            cache = load(cl);\n          }\n          map = cache;\n        }\n      }\n      return map.get(key);\n    }\n\n    private static java.util.Map<String, ShimTarget> load(ClassLoader cl) {\n      java.util.Map<String, ShimTarget> map = new java.util.HashMap<>();\n      java.io.InputStream is = (cl != null ? cl : ClassLoader.getSystemClassLoader())\n          .getResourceAsStream(\"META-INF/btrace/shims.index\");\n      if (is == null) return map;\n      try (java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(is, java.nio.charset.StandardCharsets.UTF_8))) {\n        String line;\n        while ((line = br.readLine()) != null) {\n          line = line.trim();\n          if (line.isEmpty() || line.startsWith(\"#\")) continue;\n          int eq = line.indexOf('=');\n          if (eq <= 0) continue;\n          String k = line.substring(0, eq).trim();\n          String rest = line.substring(eq + 1).trim();\n          String noop = rest;\n          String thrw = null;\n          int comma = rest.indexOf(',');\n          if (comma > 0) {\n            noop = rest.substring(0, comma).trim();\n            thrw = rest.substring(comma + 1).trim();\n          }\n          map.put(k, new ShimTarget(noop, thrw));\n        }\n      } catch (Throwable ignore) {\n        // ignore; will fallback to dynamic proxy\n      }\n      return map;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/IndyDispatcher.java",
    "content": "/*\n * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.runtime;\n\nimport java.lang.invoke.CallSite;\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.MethodType;\nimport java.lang.invoke.MutableCallSite;\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.ConcurrentMap;\n\nimport org.openjdk.btrace.core.HandlerRepository;\n\n/**\n * INVOKEDYNAMIC bootstrap class for BTrace probe handler dispatch.\n *\n * <p>Works with Java 8+. Replaces the Java 15-specific {@code Indy} class that used\n * {@code defineHiddenClass}. Probe handler methods live in the probe class — defined in a\n * per-probe {@link ClassLoader} on JDK 8/9-14, or as a hidden class on JDK 15+ — and are\n * resolved via {@link MethodHandles#publicLookup()}.findStatic() — no bytecode copying\n * required.\n *\n * <p><b>Dispatch strategy:</b> every call site is a {@link MutableCallSite}. On bootstrap\n * we attempt immediate resolution; on success the MCS target is set to the resolved\n * {@link MethodHandle}; on failure the target is a self-relinking trampoline that retries\n * on every invocation until resolution succeeds.\n *\n * <p><b>Why always MutableCallSite</b> (and not {@code ConstantCallSite} even for the\n * immediate-success path): BTrace does not retransform target classes on probe detach, so\n * the INVOKEDYNAMIC call sites woven into instrumented methods persist after the probe is\n * gone. A {@code ConstantCallSite} cannot be relinked, so once it is pinned to a resolved\n * handler handle, unregistering the probe is <i>impossible</i> — the handler keeps firing\n * even after {@code BTraceRuntime} state is torn down, leading to NPEs inside the\n * instrumented application. By making every dispatch site mutable we can re-point the\n * target to a noop when {@link #invalidateProbe(String)} is called from the agent at\n * detach time. (Note: probe classes themselves are unloadable — they live in per-probe\n * ClassLoaders / hidden classes — but the residual call sites in target classes are what\n * force the mutable choice.)\n *\n * <p><b>Important:</b> This class lives in the bootstrap classloader and must not reference\n * SLF4J or any other logging framework. SLF4J initialization in the bootstrap classloader\n * context can fail, causing this class's static initializer to throw, which prevents the\n * repository from being wired up. Handler resolution failures are logged by\n * {@code HandlerRepositoryImpl.resolveHandler()} on the agent-classloader side.\n */\npublic final class IndyDispatcher {\n\n  /**\n   * Bridge to the HandlerRepository implementation (HandlerRepositoryImpl in agent CL).\n   * Set via reflection from HandlerRepositoryImpl's static initializer. May be null if\n   * bootstrap runs before the agent wiring completes — the trampoline handles that case.\n   */\n  public static volatile HandlerRepository repository = null;\n\n  /**\n   * Live call sites per probe class name (internal form). Used to invalidate all sites\n   * targeting a given probe on unregister. Entries are weak references so call sites that\n   * have become unreachable (e.g. instrumented class unloaded) don't leak.\n   */\n  private static final ConcurrentMap<String, ConcurrentLinkedQueue<WeakReference<MutableCallSite>>>\n      LIVE_SITES = new ConcurrentHashMap<>();\n\n  private static final MethodHandle RELINK_MH;\n  private static final MethodHandle NOOP_IMPL_MH;\n\n  static {\n    try {\n      MethodHandles.Lookup lookup = MethodHandles.lookup();\n      RELINK_MH =\n          lookup.findStatic(\n              IndyDispatcher.class,\n              \"relink\",\n              MethodType.methodType(\n                  MethodHandle.class,\n                  MutableCallSite.class,\n                  String.class,\n                  String.class,\n                  MethodType.class));\n      NOOP_IMPL_MH =\n          lookup.findStatic(\n              IndyDispatcher.class, \"noopImpl\", MethodType.methodType(void.class));\n    } catch (ReflectiveOperationException e) {\n      throw new ExceptionInInitializerError(e);\n    }\n  }\n\n  /**\n   * INVOKEDYNAMIC bootstrap method. Called by the JVM on first execution of each\n   * instrumented call site.\n   *\n   * <p>Always returns a {@link MutableCallSite}. If resolution succeeds immediately the\n   * target is the resolved handler; otherwise it is a self-relinking trampoline.\n   *\n   * @param caller         the lookup context of the instrumented class\n   * @param name           the handler method name (probe-prefixed, e.g. {@code \"probeName$handlerMethod\"})\n   * @param type           the method type of the call site\n   * @param probeClassName the internal name of the probe class (passed as BSM constant)\n   */\n  public static CallSite bootstrap(\n      MethodHandles.Lookup caller, String name, MethodType type, String probeClassName) {\n    MutableCallSite mcs = new MutableCallSite(type);\n    MethodHandle mh = tryResolve(probeClassName, name, type);\n    if (mh != null) {\n      mcs.setTarget(mh);\n    } else {\n      mcs.setTarget(makeTrampoline(mcs, probeClassName, name, type));\n    }\n    registerSite(probeClassName, mcs);\n    return mcs;\n  }\n\n  /**\n   * Invalidate all live dispatch sites for a given probe. Called by\n   * {@code HandlerRepositoryImpl.unregisterProbe()} on detach. Each site's target is reset\n   * to a noop, so probe handler bodies are not invoked after teardown (prevents crashes\n   * when {@code BTraceRuntime} state has been disposed).\n   *\n   * <p>Sites remain registered. Note: the current implementation installs a direct noop\n   * handle (not a trampoline), so sites do not auto-rebind on re-registration — a\n   * subsequent {@code registerProbe} for the same name creates new call sites on next\n   * bootstrap, which is the common case. See TODO in {@link #invalidateProbe} body for the\n   * tradeoffs.\n   *\n   * @param probeClassName internal name of the probe class to invalidate\n   */\n  public static void invalidateProbe(String probeClassName) {\n    ConcurrentLinkedQueue<WeakReference<MutableCallSite>> q = LIVE_SITES.get(probeClassName);\n    if (q == null) {\n      return;\n    }\n    List<MutableCallSite> updated = new ArrayList<>();\n    Iterator<WeakReference<MutableCallSite>> it = q.iterator();\n    while (it.hasNext()) {\n      WeakReference<MutableCallSite> ref = it.next();\n      MutableCallSite site = ref.get();\n      if (site == null) {\n        it.remove();\n        continue;\n      }\n      // Re-install a trampoline so (a) this invocation lands on noop, and (b) if the\n      // probe is re-registered later, the next call re-runs resolution and relinks.\n      MethodType type = site.type();\n      // We no longer know the handler name here (bootstrap binds it into the trampoline).\n      // So install a direct-noop target for now — re-registration requires bootstrap to\n      // replace this MCS (the JVM caches CallSites per invokedynamic site, so the trampoline\n      // approach would only work if we also remembered the name). Direct noop is the safe\n      // choice: it eliminates the crash risk, which is the stated contract.\n      site.setTarget(noop(type));\n      updated.add(site);\n    }\n    if (!updated.isEmpty()) {\n      MutableCallSite.syncAll(updated.toArray(new MutableCallSite[0]));\n    }\n  }\n\n  /**\n   * Attempts a single resolution pass. Returns null when the repository is not yet wired\n   * or when the repository itself returns null / throws.\n   */\n  private static MethodHandle tryResolve(String probeClassName, String name, MethodType type) {\n    HandlerRepository repo = repository;\n    if (repo == null) {\n      return null;\n    }\n    try {\n      return repo.resolveHandler(probeClassName, name, type);\n    } catch (Throwable t) {\n      // Logged on the agent-CL side (HandlerRepositoryImpl). SLF4J must not be\n      // referenced from bootstrap-CL code. The trampoline will retry on next call.\n      return null;\n    }\n  }\n\n  /**\n   * Build a trampoline handle of the call site's type that, on invocation, calls\n   * {@link #relink} to obtain a real target. The result of relink is then invoked with the\n   * original call-site arguments. Once relink returns the resolved MethodHandle, it also\n   * updates {@code mcs.setTarget(...)} so subsequent invocations bypass this trampoline.\n   */\n  private static MethodHandle makeTrampoline(\n      MutableCallSite mcs, String probeClassName, String name, MethodType type) {\n    MethodHandle relinker =\n        MethodHandles.insertArguments(RELINK_MH, 0, mcs, probeClassName, name, type);\n    return MethodHandles.foldArguments(MethodHandles.exactInvoker(type), relinker);\n  }\n\n  /**\n   * Relink hook invoked by the trampoline. Tries to resolve; on success, updates the\n   * MutableCallSite's target so future invocations go directly to the resolved handle.\n   * On failure, returns a noop handle (this single invocation is a no-op, but the\n   * trampoline remains installed — next invocation will retry again).\n   */\n  @SuppressWarnings(\"unused\") // referenced via MethodHandle\n  private static MethodHandle relink(\n      MutableCallSite mcs, String probeClassName, String name, MethodType type) {\n    MethodHandle resolved = tryResolve(probeClassName, name, type);\n    if (resolved != null) {\n      mcs.setTarget(resolved);\n      MutableCallSite.syncAll(new MutableCallSite[] {mcs});\n      return resolved;\n    }\n    return noop(type);\n  }\n\n  private static void registerSite(String probeClassName, MutableCallSite mcs) {\n    LIVE_SITES\n        .computeIfAbsent(probeClassName, k -> new ConcurrentLinkedQueue<>())\n        .add(new WeakReference<>(mcs));\n  }\n\n  /**\n   * Noop handle of the given call-site type. Accepts the call site's argument list and\n   * produces the default value for its return type (void / null / 0) without invoking any\n   * probe code. Used by {@link #invalidateProbe(String)} and by the trampoline when\n   * resolution is still failing.\n   */\n  private static MethodHandle noop(MethodType type) {\n    Class<?> rt = type.returnType();\n    MethodHandle body;\n    if (rt == void.class) {\n      body = NOOP_IMPL_MH; // () -> void\n    } else {\n      // constant(T, defaultValueFor(T)) has type () -> T; dropArguments adds the call-site args.\n      body = MethodHandles.constant(rt, defaultValueFor(rt));\n    }\n    return MethodHandles.dropArguments(body, 0, type.parameterArray());\n  }\n\n  public static Object defaultValueFor(Class<?> t) {\n    if (!t.isPrimitive()) return null;\n    if (t == boolean.class) return Boolean.FALSE;\n    if (t == byte.class) return (byte) 0;\n    if (t == short.class) return (short) 0;\n    if (t == char.class) return (char) 0;\n    if (t == int.class) return 0;\n    if (t == long.class) return 0L;\n    if (t == float.class) return 0f;\n    if (t == double.class) return 0d;\n    return null;\n  }\n\n  @SuppressWarnings(\"unused\") // referenced via MethodHandle\n  private static void noopImpl() {}\n\n  /** Test-only: clear the live-sites registry so tests don't see residue from prior runs. */\n  static void __resetForTests() {\n    LIVE_SITES.clear();\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/Interval.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.runtime;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic class Interval implements Comparable<Interval> {\n  private static final Pattern INTERVAL_PATTERN = Pattern.compile(\"\\\\((\\\\d+)[,;]\\\\s*(\\\\d+)\\\\)\");\n  private static final Pattern COMP_PATTERN =\n      Pattern.compile(\"(<|>|=|<=|>=|GT|LT|GE|LE|EQ)?(\\\\d+)\");\n\n  private int a, b;\n\n  public Interval(int a, int b) {\n    this.a = a;\n    this.b = b;\n  }\n\n  public static Interval eq(int value) {\n    return new Interval(value, value);\n  }\n\n  public static Interval ge(int value) {\n    return new Interval(value, Integer.MAX_VALUE);\n  }\n\n  public static Interval gt(int value) {\n    return new Interval(\n        value != Integer.MAX_VALUE ? value + 1 : Integer.MAX_VALUE, Integer.MAX_VALUE);\n  }\n\n  public static Interval le(int value) {\n    return new Interval(Integer.MIN_VALUE, value);\n  }\n\n  public static Interval lt(int value) {\n    return new Interval(\n        Integer.MIN_VALUE, value != Integer.MIN_VALUE ? value - 1 : Integer.MIN_VALUE);\n  }\n\n  public static Interval all() {\n    return new Interval(Integer.MIN_VALUE, Integer.MAX_VALUE);\n  }\n\n  public static Interval none() {\n    return new Interval(Integer.MAX_VALUE, Integer.MIN_VALUE);\n  }\n\n  public static List<Interval> union(Collection<Interval> intervals) {\n    Set<Interval> itvSet = new TreeSet<>(intervals);\n\n    Iterator<Interval> iter = itvSet.iterator();\n    Interval previous = null;\n    while (iter.hasNext()) {\n      if (previous == null) {\n        previous = iter.next();\n        continue;\n      }\n      Interval current = iter.next();\n      if (current.a <= (previous.b != Integer.MAX_VALUE ? previous.b + 1 : Integer.MAX_VALUE)) {\n        previous.b = current.b;\n        iter.remove();\n      } else {\n        previous = current;\n      }\n    }\n    return new ArrayList<>(itvSet);\n  }\n\n  public static List<Interval> invert(Collection<Interval> intervals) {\n    Interval remainder = new Interval(Integer.MIN_VALUE, Integer.MAX_VALUE);\n    Set<Interval> sorted = new TreeSet<>(union(intervals));\n    List<Interval> result = new ArrayList<>();\n    for (Interval i : sorted) {\n      if (i.isAll()) {\n        return Collections.singletonList(none());\n      }\n      if (i.a <= remainder.a) {\n        if (i.b > remainder.a) remainder.a = i.b != Integer.MAX_VALUE ? i.b + 1 : i.b;\n      } else {\n        result.add(new Interval(remainder.a, i.a - 1));\n        if (i.b < remainder.b) {\n          remainder.a = i.b + 1;\n        } else {\n          remainder = null;\n          break;\n        }\n      }\n    }\n    if (remainder != null) {\n      result.add(remainder);\n    }\n    return result;\n  }\n\n  public static Interval fromString(String s) {\n    Matcher m = INTERVAL_PATTERN.matcher(s);\n    if (m.matches()) {\n      int a = Integer.parseInt(m.group(1));\n      int b = Integer.parseInt(m.group(2));\n      return new Interval(a, b);\n    } else {\n      m = COMP_PATTERN.matcher(s);\n      if (m.matches()) {\n        String operator = m.group(1) != null ? m.group(1) : \"\";\n        String val = m.group(2);\n        int level = Integer.parseInt(val);\n        switch (operator) {\n          case \"EQ\":\n          case \"=\":\n            {\n              return eq(level);\n            }\n          case \"LT\":\n          case \"<\":\n            {\n              return lt(level);\n            }\n          case \"GT\":\n          case \">\":\n            {\n              return gt(level);\n            }\n          case \"LE\":\n          case \"<=\":\n            {\n              return le(level);\n            }\n          case \"GE\":\n          case \">=\":\n          case \"\":\n            {\n              return ge(level);\n            }\n          default:\n            {\n              throw new IllegalArgumentException(\"Unrecognized operator: \" + operator);\n            }\n        }\n      }\n    }\n    throw new IllegalArgumentException(\"Invalid level declaration: \" + s);\n  }\n\n  public int getA() {\n    return a;\n  }\n\n  public int getB() {\n    return b;\n  }\n\n  public boolean isAll() {\n    return a == Integer.MIN_VALUE && b == Integer.MAX_VALUE;\n  }\n\n  public boolean isNone() {\n    return a == Integer.MAX_VALUE;\n  }\n\n  @Override\n  public int compareTo(Interval o) {\n    if (a < o.a) {\n      return -1;\n    } else if (a > o.a) {\n      return 1;\n    } else {\n      return Integer.compare(b, o.b);\n    }\n  }\n\n  @Override\n  public int hashCode() {\n    int hash = 3;\n    hash = 23 * hash + a;\n    hash = 23 * hash + b;\n    return hash;\n  }\n\n  @Override\n  public boolean equals(Object obj) {\n    if (obj == null) {\n      return false;\n    }\n    if (getClass() != obj.getClass()) {\n      return false;\n    }\n    Interval other = (Interval) obj;\n    if (a != other.a) {\n      return false;\n    }\n    return b == other.b;\n  }\n\n  @Override\n  public String toString() {\n    if (a == Integer.MIN_VALUE) {\n      if (b != Integer.MAX_VALUE) {\n        return \"LE\" + b;\n      }\n    } else {\n      if (b == Integer.MAX_VALUE) {\n        return \"GE\" + a;\n      }\n    }\n    return \"(\" + a + \";\" + b + \")\";\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/JfrEventFactoryImpl.java",
    "content": "package org.openjdk.btrace.runtime;\n\nimport static org.openjdk.btrace.core.annotations.Event.FieldKind.BOOLEANFLAG;\nimport static org.openjdk.btrace.core.annotations.Event.FieldKind.DATAAMOUNT;\nimport static org.openjdk.btrace.core.annotations.Event.FieldKind.FREQUENCY;\nimport static org.openjdk.btrace.core.annotations.Event.FieldKind.MEMORYADDRESS;\nimport static org.openjdk.btrace.core.annotations.Event.FieldKind.PERCENTAGE;\nimport static org.openjdk.btrace.core.annotations.Event.FieldKind.TIMESPAN;\nimport static org.openjdk.btrace.core.annotations.Event.FieldKind.TIMESTAMP;\nimport static org.openjdk.btrace.core.annotations.Event.FieldKind.UNSIGNED;\nimport static org.openjdk.btrace.core.annotations.Event.FieldType.BOOLEAN;\nimport static org.openjdk.btrace.core.annotations.Event.FieldType.BYTE;\nimport static org.openjdk.btrace.core.annotations.Event.FieldType.CHAR;\nimport static org.openjdk.btrace.core.annotations.Event.FieldType.DOUBLE;\nimport static org.openjdk.btrace.core.annotations.Event.FieldType.FLOAT;\nimport static org.openjdk.btrace.core.annotations.Event.FieldType.INT;\nimport static org.openjdk.btrace.core.annotations.Event.FieldType.LONG;\nimport static org.openjdk.btrace.core.annotations.Event.FieldType.SHORT;\nimport static org.openjdk.btrace.core.annotations.Event.FieldType.STRING;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport jdk.jfr.AnnotationElement;\nimport jdk.jfr.BooleanFlag;\nimport jdk.jfr.Category;\nimport jdk.jfr.DataAmount;\nimport jdk.jfr.Description;\nimport jdk.jfr.Event;\nimport jdk.jfr.EventFactory;\nimport jdk.jfr.FlightRecorder;\nimport jdk.jfr.Frequency;\nimport jdk.jfr.Label;\nimport jdk.jfr.MemoryAddress;\nimport jdk.jfr.Name;\nimport jdk.jfr.Percentage;\nimport jdk.jfr.Period;\nimport jdk.jfr.Registered;\nimport jdk.jfr.StackTrace;\nimport jdk.jfr.Timespan;\nimport jdk.jfr.Timestamp;\nimport jdk.jfr.Unsigned;\nimport jdk.jfr.ValueDescriptor;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nfinal class JfrEventFactoryImpl implements JfrEvent.Factory {\n  private static final Logger log = LoggerFactory.getLogger(JfrEventFactoryImpl.class);\n\n  private static final Map<String, Class<?>> VALUE_TYPES;\n  private static final Map<String, Class<? extends Annotation>> SPECIFICATION_ANNOTATION_TYPES;\n\n  static {\n    VALUE_TYPES = new HashMap<>();\n    SPECIFICATION_ANNOTATION_TYPES = new HashMap<>();\n    VALUE_TYPES.put(BYTE.name(), byte.class);\n    VALUE_TYPES.put(BOOLEAN.name(), boolean.class);\n    VALUE_TYPES.put(CHAR.name(), char.class);\n    VALUE_TYPES.put(INT.name(), int.class);\n    VALUE_TYPES.put(SHORT.name(), short.class);\n    VALUE_TYPES.put(FLOAT.name(), float.class);\n    VALUE_TYPES.put(LONG.name(), long.class);\n    VALUE_TYPES.put(DOUBLE.name(), double.class);\n    VALUE_TYPES.put(STRING.name(), String.class);\n\n    SPECIFICATION_ANNOTATION_TYPES.put(TIMESTAMP.name(), Timestamp.class);\n    SPECIFICATION_ANNOTATION_TYPES.put(TIMESPAN.name(), Timespan.class);\n    SPECIFICATION_ANNOTATION_TYPES.put(DATAAMOUNT.name(), DataAmount.class);\n    SPECIFICATION_ANNOTATION_TYPES.put(FREQUENCY.name(), Frequency.class);\n    SPECIFICATION_ANNOTATION_TYPES.put(MEMORYADDRESS.name(), MemoryAddress.class);\n    SPECIFICATION_ANNOTATION_TYPES.put(PERCENTAGE.name(), Percentage.class);\n    SPECIFICATION_ANNOTATION_TYPES.put(BOOLEANFLAG.name(), BooleanFlag.class);\n    SPECIFICATION_ANNOTATION_TYPES.put(UNSIGNED.name(), Unsigned.class);\n  }\n\n  private final EventFactory eventFactory;\n  private final Map<String, Integer> fieldIndex = new HashMap<>();\n\n  private Runnable periodicHook = null;\n\n  JfrEventFactoryImpl(JfrEvent.Template template) {\n    List<AnnotationElement> defAnnotations = new ArrayList<>();\n    List<ValueDescriptor> defFields = new ArrayList<>();\n    defAnnotations.add(new AnnotationElement(Name.class, template.getName()));\n    defAnnotations.add(new AnnotationElement(Registered.class, true));\n    defAnnotations.add(new AnnotationElement(StackTrace.class, template.isStacktrace()));\n    if (template.getLabel() != null) {\n      defAnnotations.add(new AnnotationElement(Label.class, template.getLabel()));\n    }\n    if (template.getDescription() != null) {\n      defAnnotations.add(new AnnotationElement(Description.class, template.getDescription()));\n    }\n    if (template.getCategory() != null) {\n      defAnnotations.add(new AnnotationElement(Category.class, template.getCategory()));\n    }\n    if (template.getPeriod() != null) {\n      defAnnotations.add(new AnnotationElement(Period.class, template.getPeriod()));\n    }\n\n    JfrEvent.Template.Field[] fields = template.getFields();\n    if (fields != null) {\n      for (int i = 0; i < fields.length; i++) {\n        JfrEvent.Template.Field field = fields[i];\n        List<AnnotationElement> fieldAnnotations = new ArrayList<>();\n        if (field.getDescription() != null) {\n          fieldAnnotations.add(new AnnotationElement(Description.class, field.getDescription()));\n        }\n        if (field.getLabel() != null) {\n          fieldAnnotations.add(new AnnotationElement(Label.class, field.getLabel()));\n        }\n        if (field.getSpecificationName() != null) {\n          Class<? extends Annotation> annotationType =\n              SPECIFICATION_ANNOTATION_TYPES.get(field.getSpecificationName());\n          if (annotationType != null) {\n            fieldAnnotations.add(\n                new AnnotationElement(annotationType, field.getSpecificationValue()));\n          }\n        }\n        ValueDescriptor vd =\n            new ValueDescriptor(\n                VALUE_TYPES.get(field.getType()), field.getName(), fieldAnnotations);\n\n        defFields.add(vd);\n        fieldIndex.put(field.getName(), i);\n      }\n    }\n    if (log.isDebugEnabled()) {\n      log.debug(\"Creating event factory: {}\", template.getName());\n    }\n    eventFactory = EventFactory.create(defAnnotations, defFields);\n    if (log.isDebugEnabled()) {\n      log.debug(\"Registering event factory: {}\", template.getName());\n    }\n    eventFactory.register();\n    if (template.getPeriod() != null && template.getPeriodicHandler() != null) {\n      addJfrPeriodicEvent(template);\n    }\n  }\n\n  @Override\n  public JfrEvent newEvent() {\n    return new JfrEventImpl(eventFactory.newEvent(), fieldIndex);\n  }\n\n  private void addJfrPeriodicEvent(JfrEvent.Template template) {\n    try {\n      Class<?> handlerClass = resolveHandlerClass(template.getOwner());\n      if (handlerClass == null) {\n        // No registered runtime — fall back to the agent's loader. Preserves the\n        // JDK 8 path (probes are defined into the agent's loader via\n        // unsafe.defineClass) and any other pre-hidden-class deployment.\n        handlerClass = Class.forName(template.getOwner());\n      }\n      Method handlerMethod =\n          handlerClass.getDeclaredMethod(template.getPeriodicHandler(), JfrEvent.class);\n      handlerMethod.setAccessible(true);\n      Runnable hook =\n          (Runnable)\n              Proxy.newProxyInstance(\n                  handlerClass.getClassLoader(),\n                  new Class[] {Runnable.class},\n                  new InvocationHandler() {\n                    @Override\n                    public Object invoke(Object proxy, Method method, Object[] args)\n                        throws Throwable {\n                      if (method.getName().equals(\"run\")) {\n                        try {\n                          JfrEvent event = newEvent();\n                          return handlerMethod.invoke(null, event);\n                        } catch (Throwable t) {\n                          log.warn(\"Periodic JFR handler invocation failed\", t);\n                          throw t;\n                        }\n                      } else {\n                        return method.invoke(this, args);\n                      }\n                    }\n                  });\n      Class<? extends Event> eClz = eventFactory.newEvent().getClass();\n      FlightRecorder.addPeriodicEvent(eClz, hook);\n      periodicHook = hook;\n    } catch (ClassNotFoundException e) {\n      StringBuilder msg = new StringBuilder(\"Unable to register periodic JFR event of type '\");\n      String eMsg = e.getMessage();\n      msg.append(eMsg.replace('/', '.'));\n      msg.append(\"'\");\n      log.info(msg.toString());\n    } catch (Throwable ignored) {\n    }\n  }\n\n  void unregister() {\n    if (periodicHook != null) {\n      FlightRecorder.removePeriodicEvent(periodicHook);\n    }\n    eventFactory.unregister();\n  }\n\n  /**\n   * Resolve the probe handler class via the runtime registry.\n   *\n   * <p>{@link Class#forName} doesn't see probes defined in isolated or hidden\n   * class loaders, so go through the registry the agent populated at\n   * defineClass time. Returns {@code null} if no runtime is registered — the\n   * caller falls back to {@code Class.forName} for deployments (notably the\n   * JDK 8 path) that define probes directly into the agent's loader.\n   */\n  private static Class<?> resolveHandlerClass(String probeName) {\n    BTraceRuntimeImplBase rt = BTraceRuntimeAccessImpl.getRuntime(probeName);\n    return rt != null ? rt.getProbeClass() : null;\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/JfrEventImpl.java",
    "content": "package org.openjdk.btrace.runtime;\n\nimport java.util.Map;\nimport jdk.jfr.Event;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nclass JfrEventImpl extends JfrEvent {\n  private static final Logger log = LoggerFactory.getLogger(JfrEventImpl.class);\n\n  private final Event event;\n  private final Map<String, Integer> fieldIndex;\n\n  JfrEventImpl(Event event, Map<String, Integer> fieldIndex) {\n    this.event = event;\n    this.fieldIndex = fieldIndex;\n  }\n\n  @Override\n  public JfrEvent withValue(String fieldName, byte value) {\n    if (checkField(fieldName)) {\n      event.set(fieldIndex.get(fieldName), value);\n    }\n    return this;\n  }\n\n  @Override\n  public JfrEvent withValue(String fieldName, boolean value) {\n    if (checkField(fieldName)) {\n      event.set(fieldIndex.get(fieldName), value);\n    }\n    return this;\n  }\n\n  @Override\n  public JfrEvent withValue(String fieldName, char value) {\n    if (checkField(fieldName)) {\n      event.set(fieldIndex.get(fieldName), value);\n    }\n    return this;\n  }\n\n  @Override\n  public JfrEvent withValue(String fieldName, short value) {\n    if (checkField(fieldName)) {\n      event.set(fieldIndex.get(fieldName), value);\n    }\n    return this;\n  }\n\n  @Override\n  public JfrEvent withValue(String fieldName, int value) {\n    if (checkField(fieldName)) {\n      event.set(fieldIndex.get(fieldName), value);\n    }\n    return this;\n  }\n\n  @Override\n  public JfrEvent withValue(String fieldName, float value) {\n    if (checkField(fieldName)) {\n      event.set(fieldIndex.get(fieldName), value);\n    }\n    return this;\n  }\n\n  @Override\n  public JfrEvent withValue(String fieldName, long value) {\n    if (checkField(fieldName)) {\n      event.set(fieldIndex.get(fieldName), value);\n    }\n    return this;\n  }\n\n  @Override\n  public JfrEvent withValue(String fieldName, double value) {\n    if (checkField(fieldName)) {\n      event.set(fieldIndex.get(fieldName), value);\n    }\n    return this;\n  }\n\n  @Override\n  public JfrEvent withValue(String fieldName, String value) {\n    if (checkField(fieldName)) {\n      event.set(fieldIndex.get(fieldName), value);\n    }\n    return this;\n  }\n\n  @Override\n  public void commit() {\n    event.commit();\n  }\n\n  @Override\n  public boolean shouldCommit() {\n    return event.shouldCommit();\n  }\n\n  @Override\n  public void begin() {\n    event.begin();\n  }\n\n  @Override\n  public void end() {\n    event.end();\n  }\n\n  private boolean checkField(String fieldName) {\n    if (!fieldIndex.containsKey(fieldName)) {\n      if (log.isDebugEnabled()) {\n        log.debug(\"Invalid event field: {}\", fieldName);\n      }\n      return false;\n    }\n    return true;\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/NullPerfReaderImpl.java",
    "content": "/*\n * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.runtime;\n\n/**\n * Dummy perf reader that throws UnsupportedOperationException always. We use this when we don't\n * have access to jvmstat classes.\n *\n * @author A. Sundararajan\n */\nfinal class NullPerfReaderImpl implements PerfReader {\n  @Override\n  public int perfInt(String name) {\n    throw new UnsupportedOperationException(\n        \"jvmstat not supported, do you have tools.jar (or classes.jar) in CLASSPATH?\");\n  }\n\n  @Override\n  public long perfLong(String name) {\n    throw new UnsupportedOperationException(\n        \"jvmstat not supported, do you have tools.jar (or classes.jar) in CLASSPATH?\");\n  }\n\n  @Override\n  public String perfString(String name) {\n    throw new UnsupportedOperationException(\n        \"jvmstat not supported, do you have tools.jar (or classes.jar) in CLASSPATH?\");\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/PerfReader.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.runtime;\n\n/**\n * This interface hides jvmstat classes from the caller. The implementor of this interface should\n * read perf counters and return the value.\n *\n * @author A. Sundararajan\n */\npublic interface PerfReader {\n  int perfInt(String name);\n\n  long perfLong(String name);\n\n  String perfString(String name);\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/ProbeAnchor.java",
    "content": "/*\n * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n */\n\npackage org.openjdk.btrace.runtime;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Shared helper for probe-class isolation on the JDK 9-14 code paths.\n *\n * <p>On those paths we cannot define a probe into a hidden class yet\n * ({@code Lookup.defineHiddenClass} is JDK 15+), so to keep probes unloadable\n * we instead define each probe in a <em>fresh, throwaway {@link ClassLoader}</em>:\n *\n * <ol>\n *   <li>{@link #defineAnchor(ClassLoader)} emits a tiny, unique public \"anchor\" class into\n *       a brand-new unnamed {@code ClassLoader} (parented to the given {@code ClassLoader}).</li>\n *   <li>The caller then invokes\n *       {@code MethodHandles.privateLookupIn(anchor, lookup()).defineClass(probeBytes)}\n *       which lands the probe into the anchor's loader — i.e. the same fresh loader.</li>\n *   <li>When the probe is dropped and all {@code MethodHandle}s / {@code Class<?>}\n *       references are cleared, the loader becomes unreachable and the probe class\n *       is eligible for unload.</li>\n * </ol>\n *\n * <p>Kept in the JDK 8 source set so it is visible to both the {@code java9}\n * and {@code java11} source sets through the main compile output.\n */\nfinal class ProbeAnchor {\n  private static final AtomicLong ANCHOR_SEQ = new AtomicLong();\n\n  private ProbeAnchor() {}\n\n  /**\n   * Emit a tiny, unique, public anchor class into a brand-new unnamed\n   * {@link ClassLoader} so that a subsequent\n   * {@code privateLookupIn(anchor, ...).defineClass(probeBytes)} places the probe\n   * into that isolated loader.\n   *\n   * @param parent the parent ClassLoader. Allows probe to resolve classes (e.g., BTraceUtils)\n   *     from the agent's ClassLoader.\n   */\n  static Class<?> defineAnchor(ClassLoader parent) {\n    long seq = ANCHOR_SEQ.incrementAndGet();\n    final String binaryName = \"org.openjdk.btrace.runtime.auxiliary.Anchor$\" + seq;\n    final byte[] bytes = generateAnchorBytes(binaryName.replace('.', '/'));\n    ClassLoader cl = new ClassLoader(parent) {\n      @Override\n      protected Class<?> findClass(String name) throws ClassNotFoundException {\n        if (name.equals(binaryName)) {\n          return defineClass(name, bytes, 0, bytes.length);\n        }\n        throw new ClassNotFoundException(name);\n      }\n    };\n    try {\n      return Class.forName(binaryName, true, cl);\n    } catch (ClassNotFoundException e) {\n      throw new IllegalStateException(\"failed to define probe anchor class\", e);\n    }\n  }\n\n  /**\n   * Hand-assembled class file for:\n   * <pre>public final class &lt;internalName&gt; { public &lt;init&gt;() { super(); } }</pre>\n   * No ASM dependency on the runtime module's classpath.\n   */\n  static byte[] generateAnchorBytes(String internalName) {\n    // Build a minimal class file targeting version 52 (Java 8) — works on 9+.\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    DataOutputStream dos = new DataOutputStream(baos);\n    try {\n      // Constant pool entries:\n      //  #1 Methodref  #2.#3     -> java/lang/Object.\"<init>\":()V\n      //  #2 Class      #4        -> java/lang/Object\n      //  #3 NameAndType #5:#6    -> <init>:()V\n      //  #4 Utf8       java/lang/Object\n      //  #5 Utf8       <init>\n      //  #6 Utf8       ()V\n      //  #7 Class      #8        -> this class\n      //  #8 Utf8       internalName\n      //  #9 Utf8       Code\n      dos.writeInt(0xCAFEBABE);\n      dos.writeShort(0); // minor\n      dos.writeShort(52); // major (Java 8 classfile)\n      dos.writeShort(10); // constant_pool_count = entries + 1\n      // #1 Methodref\n      dos.writeByte(10);\n      dos.writeShort(2);\n      dos.writeShort(3);\n      // #2 Class java/lang/Object\n      dos.writeByte(7);\n      dos.writeShort(4);\n      // #3 NameAndType <init>:()V\n      dos.writeByte(12);\n      dos.writeShort(5);\n      dos.writeShort(6);\n      // #4 Utf8 \"java/lang/Object\"\n      dos.writeByte(1);\n      dos.writeUTF(\"java/lang/Object\");\n      // #5 Utf8 \"<init>\"\n      dos.writeByte(1);\n      dos.writeUTF(\"<init>\");\n      // #6 Utf8 \"()V\"\n      dos.writeByte(1);\n      dos.writeUTF(\"()V\");\n      // #7 Class this\n      dos.writeByte(7);\n      dos.writeShort(8);\n      // #8 Utf8 internalName\n      dos.writeByte(1);\n      dos.writeUTF(internalName);\n      // #9 Utf8 \"Code\"\n      dos.writeByte(1);\n      dos.writeUTF(\"Code\");\n\n      // access_flags: public(0x0001) + final(0x0010) + super(0x0020)\n      dos.writeShort(0x0001 | 0x0010 | 0x0020);\n      dos.writeShort(7); // this_class\n      dos.writeShort(2); // super_class (Object)\n      dos.writeShort(0); // interfaces_count\n      dos.writeShort(0); // fields_count\n\n      // methods_count = 1  (public <init>()V)\n      dos.writeShort(1);\n      dos.writeShort(0x0001); // access_flags = public\n      dos.writeShort(5); // name_index = <init>\n      dos.writeShort(6); // descriptor_index = ()V\n      dos.writeShort(1); // attributes_count = 1 (Code)\n\n      // Code attribute bytes: aload_0; invokespecial #1; return\n      byte[] codeBytes = new byte[] {\n          0x2A,                    // aload_0\n          (byte) 0xB7, 0x00, 0x01, // invokespecial #1\n          (byte) 0xB1              // return\n      };\n      // attribute_length = 2(max_stack)+2(max_locals)+4(code_length)+code.length+2(exc)+2(attrs)\n      int attrLen = 2 + 2 + 4 + codeBytes.length + 2 + 2;\n      dos.writeShort(9);        // attribute_name_index = \"Code\"\n      dos.writeInt(attrLen);\n      dos.writeShort(1);        // max_stack\n      dos.writeShort(1);        // max_locals\n      dos.writeInt(codeBytes.length);\n      dos.write(codeBytes);\n      dos.writeShort(0);        // exception_table_length\n      dos.writeShort(0);        // attributes_count (inside Code)\n\n      dos.writeShort(0); // class attributes_count\n      dos.flush();\n      return baos.toByteArray();\n    } catch (IOException e) {\n      throw new IllegalStateException(\"failed to assemble anchor class bytes\", e);\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/XMLSerializer.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.runtime;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.io.Writer;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.nio.charset.Charset;\nimport java.nio.charset.CharsetEncoder;\nimport java.security.AccessController;\nimport java.security.PrivilegedAction;\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\n/**\n * This class serializes an object to XML. This class handles circular references by generating ID\n * and IDREF attributes.\n *\n * @author A. Sundararajan\n */\nfinal class XMLSerializer {\n  private static final String ID = \"id\";\n  private static final String IDREF = \"idref\";\n  private static final String CLASS = \"class\";\n  // do not create me!\n  private XMLSerializer() {}\n\n  /** Write an object as an XML document to the out. */\n  public static void write(Object obj, Writer out) throws IOException {\n    if (obj == null || out == null) {\n      throw new NullPointerException();\n    }\n    Serializer s = new Serializer(out);\n    s.write(obj);\n    out.flush();\n  }\n\n  /** Return XML document string for the given object. */\n  public static String toXML(Object obj) throws IOException {\n    if (obj == null) {\n      throw new NullPointerException();\n    }\n    StringWriter sw = new StringWriter();\n    write(obj, sw);\n    return sw.toString();\n  }\n\n  public static void main(String[] args) throws IOException {\n    if (args.length > 0) {\n      System.out.println(toXML(args));\n    } else {\n      System.out.println(toXML(XMLSerializer.class));\n    }\n  }\n\n  // class that handles XML serialization\n  private static class Serializer {\n    private static final CharsetEncoder encoder = Charset.forName(\"8859_1\").newEncoder();\n\n    // out on which we will write XML\n    private final PrintWriter out;\n    // map to maintain objects serialized already\n    private final Map<Object, String> objToId;\n    // next object id (unique id for objects)\n    private long nextId;\n\n    Serializer(Writer writer) {\n      if (writer instanceof PrintWriter) {\n        out = (PrintWriter) writer;\n      } else {\n        out = new PrintWriter(writer);\n      }\n      objToId = new IdentityHashMap<>();\n      writeln(\"<?xml version='1.0' encoding='ISO-8859-1'?>\");\n    }\n\n    private static Field[] getAllFields(Class clazz) {\n      return AccessController.doPrivileged(\n          (PrivilegedAction<Field[]>)\n              () -> {\n                try {\n                  Field[] fields = clazz.getDeclaredFields();\n                  for (Field f : fields) {\n                    f.setAccessible(true);\n                  }\n                  return fields;\n                } catch (RuntimeException re) {\n                  throw re;\n                } catch (Exception exp) {\n                  throw new RuntimeException(exp);\n                }\n              });\n    }\n\n    private static String encodeTagName(String str) {\n      return str.replace(\"$\", \"d-\");\n    }\n\n    private static String quote(int code) {\n      switch (code) {\n        case '&':\n          return \"&amp;\";\n        case '<':\n          return \"&lt;\";\n        case '>':\n          return \"&gt;\";\n        case '\"':\n          return \"&quot;\";\n        case '\\'':\n          return \"&apos;\";\n          // case '\\r': return \"&#13;\";\n        default:\n          return null;\n      }\n    }\n\n    private static boolean isValidCharCode(int code) {\n      return (0x0020 <= code && code <= 0xD7FF)\n          || (0x000A == code)\n          || (0x0009 == code)\n          || (0x000D == code)\n          || (0xE000 <= code && code <= 0xFFFD)\n          || (0x10000 <= code && code <= 0x10ffff);\n    }\n\n    private static String encodeCode(int code) {\n      return \"<char cp=\\\"#\" + Integer.toString(code, 16) + \"\\\"/>\";\n    }\n\n    private static String encodeText(char ch) {\n      return encodeText(new char[] {ch});\n    }\n\n    private static String encodeText(char[] array) {\n      return encodeText(new String(array));\n    }\n\n    private static String encodeText(String string) {\n      StringBuilder sb = new StringBuilder();\n      int index = 0;\n      int len = string.length();\n      while (index < len) {\n        int point = string.codePointAt(index);\n        int count = Character.charCount(point);\n        if (isValidCharCode(point)) {\n          if (encoder.canEncode(string.substring(index, index + count))) {\n            String value = quote(point);\n            if (value != null) {\n              sb.append(value);\n            } else {\n              sb.appendCodePoint(point);\n            }\n          } else {\n            sb.append(\"&#x\");\n            sb.append(Integer.toString(point, 16));\n            sb.append(';');\n          }\n          index += count;\n        } else {\n          sb.append(encodeCode(string.charAt(index)));\n          index++;\n        }\n      }\n      return sb.toString();\n    }\n\n    void write(Object obj) {\n      if (obj instanceof Class) {\n        write(\"class\", obj);\n      } else {\n        write(\"object\", obj);\n      }\n    }\n\n    void write(String name, Object obj) {\n      name = encodeTagName(name);\n      // check null\n      if (obj == null) {\n        out.print('<');\n        out.print(name);\n        out.print(\">null</\");\n        out.print(name);\n        writeln('>');\n        return;\n      }\n\n      // check for circularity\n      if (hasSeenAlready(name, obj)) {\n        return;\n      }\n\n      Class clazz = obj.getClass();\n      if (clazz.isArray()) {\n        writeArray(name, obj);\n      } else {\n        writeObject(name, obj);\n      }\n    }\n\n    private String nextObjectId(Object obj) {\n      return Long.toString(nextId++);\n    }\n\n    private void writeln(String str) {\n      out.print(str);\n      out.print(\"\\r\\n\");\n    }\n\n    private void writeln(char ch) {\n      out.print(ch);\n      out.print(\"\\r\\n\");\n    }\n\n    private void writeln() {\n      out.print(\"\\r\\n\");\n    }\n\n    private void writeAttribute(String name, String value) {\n      out.print(name);\n      out.print(\"=\\\"\");\n      out.print(value);\n      out.print(\"\\\"\");\n    }\n\n    private void writeIdProperty(Object obj) {\n      String id = nextObjectId(obj);\n      writeAttribute(ID, id);\n      objToId.put(obj, id);\n    }\n\n    private boolean hasSeenAlready(String name, Object obj) {\n      String id = objToId.get(obj);\n      if (id != null) {\n        out.print('<');\n        out.print(name);\n        out.print(' ');\n        writeAttribute(IDREF, id);\n        writeln(\"/>\");\n        return true;\n      } else {\n        return false;\n      }\n    }\n\n    private void arrayStart(String name, Object obj) {\n      objectStart(name, obj);\n    }\n\n    private void arrayEnd(String name, Object obj) {\n      objectEnd(name, obj);\n    }\n\n    private void writeArray(String name, Object array) {\n      arrayStart(name, array);\n      int len = Array.getLength(array);\n      if (len == 0) {\n        arrayEnd(name, array);\n        return;\n      }\n      Class clazz = array.getClass().getComponentType();\n      writeln(\"<elements>\");\n      if (clazz.isPrimitive()) {\n        if (clazz == Character.TYPE) {\n          out.print(encodeText((char[]) array));\n        } else {\n          for (int index = 0; index < len; index++) {\n            out.print(Array.get(array, index));\n            if (index != len - 1) {\n              out.print(\", \");\n            }\n          }\n        }\n        writeln();\n      } else {\n        for (int index = 0; index < len; index++) {\n          write(\"li\", Array.get(array, index));\n        }\n      }\n      writeln(\"</elements>\");\n      arrayEnd(name, array);\n    }\n\n    private void objectStart(String name, Object obj) {\n      out.print('<');\n      out.print(name);\n      out.print(' ');\n      writeIdProperty(obj);\n      writeln('>');\n      write(CLASS, obj.getClass());\n    }\n\n    private void objectEnd(String name, Object obj) {\n      out.print(\"</\");\n      out.print(name);\n      writeln('>');\n    }\n\n    private void writeObject(String name, Object obj) {\n      objectStart(name, obj);\n      if (obj instanceof Class) {\n        Class clazz = (Class) obj;\n        writeStaticFields(clazz);\n        write(\"name\", clazz.getName());\n        Object loader = clazz.getClassLoader();\n        if (loader != null) {\n          write(\"loader\", loader);\n        }\n        Object protDomain = clazz.getProtectionDomain();\n        if (protDomain != null) {\n          write(\"protectionDomain\", protDomain);\n        }\n        Object[] signers = clazz.getSigners();\n        if (signers != null && signers.length > 0) {\n          write(\"signers\", signers);\n        }\n        Class sc = clazz.getSuperclass();\n        if (sc != null) {\n          writeln(\"<extends>\");\n          write(\"class\", sc);\n          writeln(\"</extends>\");\n        }\n        Class[] interfaces = clazz.getInterfaces();\n        if (interfaces != null && interfaces.length > 0) {\n          writeln(\"<implements>\");\n          for (Class cl : interfaces) {\n            write(\"class\", cl);\n          }\n          writeln(\"</implements>\");\n        }\n      } else {\n        Class clazz = obj.getClass();\n        while (clazz != null) {\n          writeFields(obj, clazz);\n          clazz = clazz.getSuperclass();\n        }\n      }\n      objectEnd(name, obj);\n    }\n\n    private void writeStaticFields(Class clazz) {\n      Field[] fields = getAllFields(clazz);\n      if (fields.length == 0) {\n        return;\n      }\n      writeln(\"<fields>\");\n      for (Field f : fields) {\n        int modifiers = f.getModifiers();\n        if (!Modifier.isStatic(modifiers)) {\n          continue;\n        }\n        writeField(f, null);\n      }\n      writeln(\"</fields>\");\n    }\n\n    private void writeFields(Object obj, Class clazz) {\n      Field[] fields = getAllFields(clazz);\n      for (Field f : fields) {\n        int modifiers = f.getModifiers();\n        if (Modifier.isStatic(modifiers)) {\n          continue;\n        }\n        writeField(f, obj);\n      }\n    }\n\n    private void writeField(Field f, Object obj) {\n      Class type = f.getType();\n      try {\n        if (type.isPrimitive()) {\n          String name = encodeTagName(f.getName());\n          String value;\n          if (type == Character.TYPE) {\n            value = encodeText(f.getChar(obj));\n          } else {\n            value = f.get(obj).toString();\n          }\n          out.print(\"<\");\n          out.print(name);\n          out.print(\">\");\n          out.print(value);\n          out.print(\"</\");\n          out.print(name);\n          writeln('>');\n        } else {\n          write(f.getName(), f.get(obj));\n        }\n      } catch (RuntimeException re) {\n        throw re;\n      } catch (Exception exp) {\n        throw new RuntimeException(exp);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/auxiliary/Auxiliary.java",
    "content": "package org.openjdk.btrace.runtime.auxiliary;\n\nimport java.lang.invoke.MethodHandles;\n\npublic final class Auxiliary {\n  private Auxiliary() {}\n\n  /**\n   * Returns a {@link MethodHandles.Lookup} anchored on this class.\n   *\n   * <p>Probes on JDK 15+ are installed via {@code MethodHandles.Lookup.defineHiddenClass}\n   * into {@code Auxiliary}'s runtime package and require a lookup with full privilege\n   * access. Obtaining the lookup here (rather than via {@code privateLookupIn} from a\n   * caller in a different module) keeps the MODULE bit and avoids\n   * {@code IllegalAccessException} when the caller's class loader is distinct from\n   * this class's — e.g. a masked-jar deployment where the agent sits on\n   * {@code MaskedClassLoader} and {@code Auxiliary} sits on the bootstrap loader.\n   *\n   * <p>Public because the primary caller lives in the sibling package\n   * {@code org.openjdk.btrace.runtime}.\n   */\n  public static MethodHandles.Lookup lookup() {\n    return MethodHandles.lookup();\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/profiling/MethodInvocationProfiler.java",
    "content": "/*\n * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.runtime.profiling;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentLinkedDeque;\nimport org.openjdk.btrace.core.Profiler;\n\n/**\n * Implementation of {@linkplain Profiler}\n *\n * @author Jaroslav Bachorik\n */\npublic class MethodInvocationProfiler extends Profiler implements Profiler.MBeanValueProvider {\n\n  private final Collection<WeakReference<MethodInvocationRecorder>> recorders =\n      new ConcurrentLinkedDeque<>();\n  private final int expectedBlockCnt;\n  private final ThreadLocal<MethodInvocationRecorder> recorder =\n      new ThreadLocal<MethodInvocationRecorder>() {\n        @Override\n        protected MethodInvocationRecorder initialValue() {\n          MethodInvocationRecorder mir = new MethodInvocationRecorder(expectedBlockCnt);\n          recorders.add(new WeakReference<>(mir));\n          return mir;\n        }\n      };\n  private volatile Snapshot lastValidSnapshot = null;\n  private long lastTs = START_TIME;\n\n  public MethodInvocationProfiler(int expectedMethodCnt) {\n    expectedBlockCnt = expectedMethodCnt;\n  }\n\n  @Override\n  public void recordEntry(String blockName) {\n    recorder.get().recordEntry(blockName);\n  }\n\n  @Override\n  public void recordExit(String blockName, long duration) {\n    recorder.get().recordExit(blockName, duration);\n  }\n\n  @Override\n  public void reset() {\n    for (WeakReference<MethodInvocationRecorder> mirRef : recorders) {\n      MethodInvocationRecorder mir = mirRef.get();\n      if (mir != null) {\n        mir.reset();\n      }\n    }\n  }\n\n  @Override\n  public Snapshot snapshot(boolean reset) {\n    Map<String, Integer> idMap = new HashMap<>();\n\n    Record[] mergedRecords = null;\n    int mergedEntries = 0, mergedCapacity = 0;\n    for (WeakReference<MethodInvocationRecorder> mirRef : recorders) {\n      MethodInvocationRecorder mir = mirRef.get();\n      if (mir == null) continue;\n\n      Record[] records = mir.getRecords(reset);\n      if (records == null || records.length == 0) continue; // just skip the empty data\n\n      if (mergedRecords == null) {\n        mergedRecords = records;\n        mergedCapacity = mergedRecords.length;\n        for (int i = 0; i < records.length; i++) {\n          if (records[i] != null) {\n            mergedEntries = i + 1;\n            idMap.put(records[i].blockName, i);\n          }\n        }\n        continue;\n      }\n\n      for (Record r : records) {\n        Integer id = idMap.get(r.blockName);\n        if (id == null) {\n          id = mergedEntries++;\n          if (mergedEntries > mergedCapacity) {\n            mergedCapacity = (((mergedEntries + 1) * 5) >> 2);\n            Record[] newRecs = new Record[mergedCapacity];\n            System.arraycopy(mergedRecords, 0, newRecs, 0, mergedEntries - 1);\n            mergedRecords = newRecs;\n          }\n          idMap.put(r.blockName, id);\n          mergedRecords[id] = r;\n        } else {\n          Record merged = mergedRecords[id];\n          merged.invocations += r.invocations;\n          merged.selfTime += r.selfTime;\n          merged.wallTime += r.wallTime;\n        }\n      }\n    }\n    Record[] rslt = new Record[mergedEntries];\n    if (mergedRecords != null) {\n      System.arraycopy(mergedRecords, 0, rslt, 0, mergedEntries);\n    }\n\n    long curTs = System.currentTimeMillis();\n    Snapshot snp = new Snapshot(rslt, lastTs, curTs);\n    lastTs = curTs;\n    lastValidSnapshot = snp;\n    return snp;\n  }\n\n  @Override\n  public Snapshot getMBeanValue() {\n    return lastValidSnapshot;\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java/org/openjdk/btrace/runtime/profiling/MethodInvocationRecorder.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage org.openjdk.btrace.runtime.profiling;\n\nimport java.util.Arrays;\nimport java.util.Deque;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.locks.LockSupport;\nimport org.openjdk.btrace.core.Profiler;\n\n/**\n * An invocation recorder class. All the invocations must be coming from the same thread (eg. by\n * making a MethodInvocationRecorder instance thread local).\n *\n * <p>The only time multithreaded access must be resolved is when a snapshot of the measured data is\n * being externally requested or the recorder is to be reset.\n *\n * <p>For this an atomic state variable is introduced to prevent simultaneous invocation processing\n * and generating snapshot/resetting.\n *\n * @author Jaroslav Bachorik\n */\nclass MethodInvocationRecorder {\n\n  private final int defaultBufferSize;\n  private final Map<String, Integer> indexMap = new HashMap<>();\n  // 0 - available; 1 - processing invocation; 2 - generating snapshot; 3 - resetting\n  private final AtomicInteger writerStatus = new AtomicInteger(0);\n  private final Deque<DelayedRecord> delayedRecords = new LinkedList<>();\n  private int stackSize = 200;\n  private int stackPtr = -1;\n  private int stackBndr = 150;\n  private Profiler.Record[] stackArr = new Profiler.Record[stackSize];\n  private int measuredSize = 0;\n  private int measuredPtr = 0;\n  private Profiler.Record[] measured = new Profiler.Record[0];\n  private long carryOver = 0L;\n  private volatile int lastIndex = 0;\n\n  public MethodInvocationRecorder(int expectedBlockCnt) {\n    defaultBufferSize = expectedBlockCnt << 8;\n    measuredSize = defaultBufferSize;\n    measured = new Profiler.Record[measuredSize];\n  }\n\n  void recordEntry(String blockName) {\n    while (true) {\n      processDelayedRecords();\n      if (writerStatus.compareAndSet(0, 1)) {\n        // System.out.println(\"== 0->1\");\n        try {\n          processEntry(blockName);\n          return;\n        } finally {\n          // System.out.println(\"== 1->0\");\n          writerStatus.compareAndSet(1, 0);\n        }\n      } else {\n        while (writerStatus.get() == 3) {\n          LockSupport.parkNanos(this, 600);\n        }\n        if (writerStatus.compareAndSet(1, 3)) {\n          // System.out.println(\"== 1->3\");\n          try {\n            delayedRecords.add(new DelayedRecord(blockName, -1L));\n            return;\n          } finally {\n            // System.out.println(\"== 3->1\");\n            writerStatus.compareAndSet(3, 1);\n          }\n        } else if (writerStatus.compareAndSet(2, 3)) {\n          // System.out.println(\"== 2->3\");\n          try {\n            delayedRecords.add(new DelayedRecord(blockName, -1L));\n            return;\n          } finally {\n            // System.out.println(\"== 3->2\");\n            writerStatus.compareAndSet(3, 2);\n          }\n        }\n      }\n      LockSupport.parkNanos(this, 600);\n    }\n  }\n\n  private void processEntry(String blockName) {\n    Profiler.Record r = new Profiler.Record(blockName);\n    addMeasured(r);\n    push(r);\n    carryOver = 0L; // clear the carryOver; not 2 subsequent calls to recordExit\n  }\n\n  void recordExit(String blockName, long duration) {\n    while (true) {\n      processDelayedRecords();\n      if (writerStatus.compareAndSet(0, 1)) {\n        // System.out.println(\"== 0->1\");\n        try {\n          processExit(blockName, duration);\n          return;\n        } finally {\n          writerStatus.compareAndSet(1, 0);\n        }\n      } else {\n        while (writerStatus.get() == 3) {\n          LockSupport.parkNanos(this, 600);\n        }\n        if (writerStatus.compareAndSet(1, 3)) {\n          try {\n            delayedRecords.add(new DelayedRecord(blockName, duration));\n            return;\n          } finally {\n            writerStatus.compareAndSet(3, 1);\n          }\n        } else if (writerStatus.compareAndSet(2, 3)) {\n          try {\n            delayedRecords.add(new DelayedRecord(blockName, duration));\n            return;\n          } finally {\n            writerStatus.compareAndSet(3, 2);\n          }\n        }\n      }\n      LockSupport.parkNanos(this, 600);\n    }\n  }\n\n  private void processExit(String blockName, long duration) {\n    Profiler.Record r = pop();\n    if (r == null) {\n      r = new Profiler.Record(blockName);\n      addMeasured(r);\n    }\n    r.wallTime = duration;\n    r.selfTime += duration - carryOver;\n    for (int i = 0; i < stackPtr; i++) {\n      if (stackArr[i].blockName.equals(blockName)) {\n        r.wallTime = 0;\n        break;\n      }\n    }\n    r.selfTimeMin = r.selfTimeMax = r.selfTime;\n    r.wallTimeMin = r.wallTimeMax = r.wallTime;\n    Profiler.Record parent = peek();\n    if (parent != null) {\n      parent.selfTime -= duration;\n    } else {\n      carryOver = duration;\n    }\n  }\n\n  private void processDelayedRecords() {\n    DelayedRecord dr = null;\n\n    while (!writerStatus.compareAndSet(0, 3)) {\n      LockSupport.parkNanos(this, 600);\n    }\n\n    try {\n      while ((dr = delayedRecords.poll()) != null) {\n        if (dr.duration == -1) {\n          processEntry(dr.blockName);\n        } else {\n          processExit(dr.blockName, dr.duration);\n        }\n      }\n    } finally {\n      writerStatus.compareAndSet(3, 0);\n    }\n  }\n\n  Profiler.Record[] getRecords(boolean reset) {\n    Profiler.Record[] recs = null;\n    try {\n      processDelayedRecords();\n\n      while (!writerStatus.compareAndSet(0, 2)) {\n        LockSupport.parkNanos(this, 600);\n      }\n      compactMeasured();\n\n      recs = new Profiler.Record[lastIndex];\n      // copy and detach the record array\n      for (int i = 0; i < recs.length; i++) {\n        Profiler.Record r = measured[i];\n        if (r != null) {\n          recs[i] = r.duplicate();\n        } else {\n          System.err.println(\"Unexpected NULL record at position \" + i + \"; ignoring\");\n        }\n      }\n\n      return recs;\n    } finally {\n      while (!writerStatus.compareAndSet(2, 0)) {\n        LockSupport.parkNanos(this, 600);\n      }\n    }\n  }\n\n  private void push(Profiler.Record r) {\n    if (stackPtr > stackBndr) {\n      stackSize = (stackSize * 3) >> 1;\n      stackBndr = (stackBndr * 3) >> 1;\n      Profiler.Record[] newStack = new Profiler.Record[stackSize];\n      System.arraycopy(stackArr, 0, newStack, 0, stackPtr + 1);\n      stackArr = newStack;\n    }\n    stackArr[++stackPtr] = r;\n    r.onStack = true;\n  }\n\n  private Profiler.Record pop() {\n    Profiler.Record r = stackPtr > -1 ? stackArr[stackPtr--] : null;\n    if (r != null) {\n      r.onStack = false;\n    }\n    return r;\n  }\n\n  private Profiler.Record peek() {\n    return stackPtr > -1 ? stackArr[stackPtr] : null;\n  }\n\n  private void addMeasured(Profiler.Record r) {\n    if (measuredPtr == measuredSize) {\n      compactMeasured();\n    }\n    measured[measuredPtr++] = r;\n  }\n\n  void reset() {\n    Profiler.Record[] newMeasured = new Profiler.Record[defaultBufferSize + stackPtr + 1];\n    try {\n      while (!writerStatus.compareAndSet(0, 4)) {\n        LockSupport.parkNanos(this, 600);\n      }\n      // System.out.println(\"== 4->0\");\n      if (stackPtr > -1) {\n        System.arraycopy(stackArr, 0, newMeasured, 0, stackPtr + 1);\n      }\n      Arrays.fill(stackArr, null);\n      indexMap.clear();\n      measuredPtr = stackPtr + 1;\n      measured = newMeasured;\n      measuredSize = measured.length;\n      lastIndex = measuredPtr;\n      carryOver = 0L;\n    } finally {\n      // System.out.println(\"== 4->0\");\n      writerStatus.compareAndSet(4, 0);\n    }\n  }\n\n  @SuppressWarnings(\"ManualMinMaxCalculation\")\n  private void compactMeasured() {\n    int lastMeasurePtr = lastIndex;\n    if (lastIndex >= measuredPtr) {\n      return;\n    }\n\n    for (int i = lastIndex; i < measuredPtr; i++) {\n      Profiler.Record m = measured[i];\n      if (!m.onStack) {\n        Integer newIndex = indexMap.get(m.blockName);\n        if (newIndex == null) {\n          newIndex = lastMeasurePtr++;\n          indexMap.put(m.blockName, newIndex);\n          measured[newIndex] = m;\n        } else {\n          Profiler.Record mr = measured[newIndex];\n          mr.selfTime += m.selfTime;\n          mr.wallTime += m.wallTime;\n          mr.invocations++;\n          mr.selfTimeMax = Math.max(m.selfTime, mr.selfTimeMax);\n          mr.selfTimeMin = Math.min(m.selfTime, mr.selfTimeMin);\n          mr.wallTimeMax = Math.max(m.wallTime, mr.wallTimeMax);\n          mr.wallTimeMin = Math.min(m.wallTime, mr.wallTimeMin);\n          m.referring = mr;\n        }\n      }\n    }\n    for (int j = 0; j < stackPtr; j++) {\n      // if the old ref is kept on stack replace it with the compacted ref\n      Profiler.Record mr = stackArr[j].referring;\n      if (mr != null) {\n        stackArr[j] = mr;\n      }\n    }\n    if ((lastMeasurePtr + stackPtr + 1) == measuredSize) {\n      int newMeasuredSize =\n          ((measuredSize * 5) >> 2) + (stackPtr + 1); // make room for the methods on the stack\n      if (newMeasuredSize == measuredSize) {\n        newMeasuredSize =\n            (measuredSize << 2) + (stackPtr + 1); // make room for the methods on the stack\n      }\n      Profiler.Record[] newMeasured = new Profiler.Record[newMeasuredSize];\n      System.arraycopy(measured, 0, newMeasured, 0, lastMeasurePtr); // copy the compacted values\n      measured = newMeasured;\n      measuredSize = newMeasuredSize;\n    }\n    System.arraycopy(\n        stackArr,\n        0,\n        measured,\n        lastMeasurePtr,\n        stackPtr + 1); // add the not processed methods on the stack\n    measuredPtr = lastMeasurePtr + stackPtr + 1; // move the pointer behind the methods on the stack\n    lastIndex = lastMeasurePtr;\n  }\n\n  private static class DelayedRecord {\n\n    private final String blockName;\n    private final long duration;\n\n    public DelayedRecord(String blockName, long duration) {\n      this.blockName = blockName;\n      this.duration = duration;\n    }\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java11/org/openjdk/btrace/runtime/BTraceRuntimeImpl_11.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.runtime;\n\nimport java.lang.instrument.Instrumentation;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.reflect.InaccessibleObjectException;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.security.AccessController;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\nimport jdk.internal.perf.Perf;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\nimport org.openjdk.btrace.runtime.auxiliary.Auxiliary;\n\n/**\n * Helper class used by BTrace built-in functions and also acts runtime \"manager\" for a specific\n * BTrace client and sends Commands to the CommandListener passed.\n *\n * @author A. Sundararajan\n * @author Christian Glencross (aggregation support)\n * @author Joachim Skeie (GC MBean support, advanced Deque manipulation)\n * @author KLynch\n */\npublic final class BTraceRuntimeImpl_11 extends BTraceRuntimeImplBase {\n  public static final class Factory extends BTraceRuntimeImplFactory<BTraceRuntimeImpl_11> {\n\n    public Factory() {\n      super(new BTraceRuntimeImpl_11());\n    }\n\n    @Override\n    public BTraceRuntimeImpl_11 getRuntime(\n        String className, ArgsMap args, CommandListener cmdListener, Instrumentation inst) {\n      return new BTraceRuntimeImpl_11(className, args, cmdListener, inst);\n    }\n\n    @Override\n    public boolean isEnabled() {\n      Runtime.Version version = Runtime.version();\n      return version.version().get(0) >= 11;\n    }\n  }\n  // perf counter variability - we always variable variability\n  private static final int V_Variable = 3;\n  // perf counter units\n  private static final int V_None = 1;\n  private static final int V_String = 5;\n  private static final int PERF_STRING_LIMIT = 256;\n\n  private static Perf perf;\n\n  private final Set<JfrEventFactoryImpl> eventFactories =\n      new java.util.concurrent.CopyOnWriteArraySet<>();\n\n  private final Method findBootstrapOrNullMtd;\n\n  private static volatile Boolean jfrAvailable = null;\n  private static final Object jfrLock = new Object();\n\n  private static boolean isJfrAvailable() {\n    if (jfrAvailable == null) {\n      synchronized (jfrLock) {\n        if (jfrAvailable == null) {\n          try {\n            Class.forName(\"jdk.jfr.EventType\");\n            jfrAvailable = Boolean.TRUE;\n          } catch (ClassNotFoundException | LinkageError e) {\n            jfrAvailable = Boolean.FALSE;\n          }\n        }\n      }\n    }\n    return jfrAvailable;\n  }\n\n  public BTraceRuntimeImpl_11() {\n    fixExports(BTraceRuntime.instrumentation);\n\n    Method m = null;\n    try {\n      m = ClassLoader.class.getDeclaredMethod(\"findBootstrapClassOrNull\", String.class);\n      m.setAccessible(true);\n    } catch (NoSuchMethodException | InaccessibleObjectException ignored) {}\n    findBootstrapOrNullMtd = m;\n  }\n\n  public BTraceRuntimeImpl_11(\n      String className, ArgsMap args, CommandListener cmdListener, Instrumentation inst) {\n    super(className, args, cmdListener, fixExports(inst));\n\n    Method m = null;\n    try {\n      m = ClassLoader.class.getDeclaredMethod(\"findBootstrapClassOrNull\", String.class);\n      m.setAccessible(true);\n    } catch (NoSuchMethodException | InaccessibleObjectException ignored) {}\n    findBootstrapOrNullMtd = m;\n  }\n\n  private static Instrumentation fixExports(Instrumentation instr) {\n    Set<Module> myModules = Collections.singleton(BTraceRuntimeImpl_11.class.getModule());\n    if (instr != null) {\n      Module javaBaseMod = int.class.getModule();\n      Module jfrMod = null;\n      if (isJfrAvailable()) {\n        try {\n          Class<?> eventTypeClass = Class.forName(\"jdk.jfr.EventType\");\n          jfrMod = eventTypeClass.getModule();\n        } catch (ClassNotFoundException | LinkageError e) {\n          // JFR not available, skip JFR module setup\n        }\n      }\n\n      // Build export/open maps only for packages actually present in the module to avoid\n      // IllegalArgumentException on newer JDKs (e.g., 25+) where some packages are removed.\n      Set<String> basePkgs = javaBaseMod.getPackages();\n      java.util.Map<String, Set<Module>> extraExports = new java.util.HashMap<>();\n      java.util.Map<String, Set<Module>> extraOpens = new java.util.HashMap<>();\n\n      if (basePkgs.contains(\"java.lang\")) {\n        extraExports.put(\"java.lang\", myModules);\n        extraOpens.put(\"java.lang\", myModules);\n      }\n      if (basePkgs.contains(\"jdk.internal.reflect\")) {\n        extraExports.put(\"jdk.internal.reflect\", myModules);\n      }\n      if (basePkgs.contains(\"jdk.internal.perf\")) {\n        extraExports.put(\"jdk.internal.perf\", myModules);\n      }\n      if (basePkgs.contains(\"sun.security.action\")) {\n        extraExports.put(\"sun.security.action\", myModules);\n      }\n\n      if (!extraExports.isEmpty() || !extraOpens.isEmpty()) {\n        instr.redefineModule(\n            javaBaseMod,\n            Collections.emptySet(),\n            extraExports,\n            extraOpens,\n            Collections.emptySet(),\n            Collections.emptyMap());\n      }\n\n      // jdk.jfr internal access - only if JFR module is available\n      if (jfrMod != null) {\n        java.util.Map<String, Set<Module>> jfrExports = new java.util.HashMap<>();\n        java.util.Map<String, Set<Module>> jfrOpens = new java.util.HashMap<>();\n        Set<String> jfrPkgs = jfrMod.getPackages();\n        if (jfrPkgs.contains(\"jdk.jfr.internal\")) {\n          jfrExports.put(\"jdk.jfr.internal\", myModules);\n        }\n        if (jfrPkgs.contains(\"jdk.jfr\")) {\n          jfrOpens.put(\"jdk.jfr\", myModules);\n        }\n        if (!jfrExports.isEmpty() || !jfrOpens.isEmpty()) {\n          instr.redefineModule(\n              jfrMod,\n              Collections.emptySet(),\n              jfrExports,\n              jfrOpens,\n              Collections.emptySet(),\n              Collections.emptyMap());\n        }\n      }\n    }\n    return instr;\n  }\n\n  @Override\n  public Class<?> defineClass(byte[] code) {\n    try {\n      // Use StackWalker instead of Reflection.getCallerClass() to avoid\n      // CallerSensitive annotation requirement (only works from bootstrap CL)\n      Class<?> caller =\n          StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)\n              .walk(frames -> frames.skip(1).findFirst())\n              .map(StackWalker.StackFrame::getDeclaringClass)\n              .orElse(null);\n      if (caller == null || !caller.getName().startsWith(\"org.openjdk.btrace.\")) {\n        throw new SecurityException(\"unsafe defineClass\");\n      }\n\n      if (Runtime.version().feature() >= 15) {\n        // Hidden class path: lifetime is tied to Class<?> reachability, so no\n        // per-probe ClassLoader is needed. defineHiddenClass(..., initialize=true, ...)\n        // also performs class initialization, so we skip the explicit newInstance()\n        // that older paths use.\n        //\n        // Reflective invocation because this source set targets JDK 11 where\n        // defineHiddenClass and Lookup.ClassOption do not exist yet. The lookup\n        // must originate inside Auxiliary so it keeps the MODULE bit in\n        // masked-jar deployments — see Auxiliary#lookup.\n        MethodHandles.Lookup lookup = Auxiliary.lookup();\n        // No ClassOption.STRONG: with the default (non-strong) policy the hidden class\n        // is unloadable as soon as the Class<?> mirror is no longer strongly reachable\n        // from outside the JVM. STRONG would tie its lifetime to the defining loader\n        // (i.e. the Auxiliary loader, shared with the agent) which defeats unloading.\n        Class<?> classOptionClass =\n            Class.forName(\"java.lang.invoke.MethodHandles$Lookup$ClassOption\");\n        Object optionArray = java.lang.reflect.Array.newInstance(classOptionClass, 0);\n        Method defineHidden =\n            MethodHandles.Lookup.class.getMethod(\n                \"defineHiddenClass\", byte[].class, boolean.class, optionArray.getClass());\n        Object hiddenLookup = defineHidden.invoke(lookup, code, true, optionArray);\n        Method lookupClassMtd = hiddenLookup.getClass().getMethod(\"lookupClass\");\n        return (Class<?>) lookupClassMtd.invoke(hiddenLookup);\n      }\n\n      // JDK 11-14: fall back to per-probe anchor + isolated ClassLoader so the\n      // probe class and its defining loader become unreachable on detach.\n      // Pass the ClassLoader that can see BTraceUtils and other agent classes.\n      ClassLoader parent = BTraceRuntimeImpl_11.class.getClassLoader();\n      if (parent == null) {\n        // If BTraceRuntimeImpl_11 is in bootstrap, use the current thread's context CL\n        parent = Thread.currentThread().getContextClassLoader();\n      }\n      Class<?> anchor = ProbeAnchor.defineAnchor(parent);\n      Class<?> clz =\n          MethodHandles.privateLookupIn(anchor, MethodHandles.lookup()).defineClass(code);\n      // initialize the class by creating a dummy instance\n      clz.getConstructor().newInstance();\n      return clz;\n    } catch (IllegalAccessException\n        | ClassNotFoundException\n        | NoSuchMethodException\n        | SecurityException\n        | InstantiationException\n        | InvocationTargetException e) {\n      Throwable root = e instanceof InvocationTargetException\n          ? ((InvocationTargetException) e).getTargetException()\n          : e;\n      throw new IllegalStateException(\n          \"BTrace probe defineClass failed on JDK \" + Runtime.version().feature(), root);\n    }\n  }\n\n  @Override\n  public void newPerfCounter(Object value, String name, String desc) {\n    Perf perf = getPerf();\n    char tc = desc.charAt(0);\n    switch (tc) {\n      case 'C':\n      case 'Z':\n      case 'B':\n      case 'S':\n      case 'I':\n      case 'J':\n      case 'F':\n      case 'D':\n        {\n          long initValue = (value != null) ? ((Number) value).longValue() : 0L;\n          ByteBuffer b = perf.createLong(name, V_Variable, V_None, initValue);\n          b.order(ByteOrder.nativeOrder());\n          counters.put(name, b);\n        }\n        break;\n\n      case '[':\n        break;\n      case 'L':\n        {\n          if (desc.equals(\"Ljava/lang/String;\")) {\n            byte[] buf;\n            if (value != null) {\n              buf = getStringBytes((String) value);\n            } else {\n              buf = new byte[PERF_STRING_LIMIT];\n              buf[0] = '\\0';\n            }\n            ByteBuffer b = perf.createByteArray(name, V_Variable, V_String, buf, buf.length);\n            counters.put(name, b);\n          }\n        }\n        break;\n    }\n  }\n\n  @Override\n  public ClassLoader getCallerClassLoader(int stackDec) {\n    AtomicInteger cont = new AtomicInteger(stackDec);\n    AtomicReference<ClassLoader> cl = new AtomicReference<>(null);\n    StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)\n        .forEach(\n            f -> {\n              if (f.getClassName().startsWith(\"org.openjdk.btrace.runtime.auxiliary.\")) {\n                return;\n              }\n              if (cont.getAndDecrement() == 0) {\n                cl.compareAndSet(null, f.getDeclaringClass().getClassLoader());\n              }\n            });\n    return cl.get();\n  }\n\n  @Override\n  public Class<?> getCallerClass(int stackDec) {\n    AtomicInteger cont = new AtomicInteger(stackDec);\n    AtomicReference<Class<?>> cl = new AtomicReference<>(null);\n    StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)\n        .forEach(\n            f -> {\n              if (f.getClassName().startsWith(\"org.openjdk.btrace.runtime.auxiliary.\")) {\n                return;\n              }\n              if (cont.getAndDecrement() == 0) {\n                cl.compareAndSet(null, f.getDeclaringClass());\n              }\n            });\n    return cl.get();\n  }\n\n  @Override\n  public int version() {\n    return Runtime.version().feature();\n  }\n\n  @Override\n  public JfrEvent.Factory createEventFactory(JfrEvent.Template template) {\n    if (!isJfrAvailable()) {\n      return null;\n    }\n    JfrEventFactoryImpl factory = new JfrEventFactoryImpl(template);\n    eventFactories.add(factory);\n    return factory;\n  }\n\n  @Override\n  public boolean isBootstrapClass(String className) {\n    try {\n      return findBootstrapOrNullMtd != null && findBootstrapOrNullMtd.invoke(ClassLoader.getSystemClassLoader(), className) != null;\n    } catch (IllegalAccessException | InvocationTargetException ignored) {}\n    return false;\n  }\n\n  @Override\n  protected void cleanupRuntime() {\n    if (isJfrAvailable()) {\n      for (JfrEventFactoryImpl factory : eventFactories) {\n        factory.unregister();\n      }\n      eventFactories.clear();\n    }\n  }\n\n  private static Perf getPerf() {\n    synchronized (BTraceRuntimeImpl_11.class) {\n      if (perf == null) {\n        try {\n          // Newer JDKs (25+) have removed Perf.GetPerfAction; prefer reflective access to getPerf()\n          Method m = Perf.class.getDeclaredMethod(\"getPerf\");\n          m.setAccessible(true);\n          perf = (Perf) m.invoke(null);\n        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {\n          // Fallback for older JDKs where GetPerfAction exists\n          try {\n            Class<?> actClz = Class.forName(\"jdk.internal.perf.Perf$GetPerfAction\");\n            Object action = actClz.getDeclaredConstructor().newInstance();\n            perf = AccessController.doPrivileged((java.security.PrivilegedAction<Perf>) action);\n          } catch (Throwable t) {\n            throw new IllegalStateException(\"Unable to acquire jdk.internal.perf.Perf instance\", t);\n          }\n        }\n      }\n    }\n    return perf;\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/main/java9/org/openjdk/btrace/runtime/BTraceRuntimeImpl_9.java",
    "content": "/*\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage org.openjdk.btrace.runtime;\n\nimport java.lang.instrument.Instrumentation;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.reflect.InaccessibleObjectException;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.security.AccessController;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\nimport jdk.internal.perf.Perf;\nimport org.openjdk.btrace.core.ArgsMap;\nimport org.openjdk.btrace.core.BTraceRuntime;\nimport org.openjdk.btrace.core.comm.CommandListener;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\nimport org.openjdk.btrace.runtime.auxiliary.Auxiliary;\n\n/**\n * Helper class used by BTrace built-in functions and also acts runtime \"manager\" for a specific\n * BTrace client and sends Commands to the CommandListener passed.\n *\n * @author A. Sundararajan\n * @author Christian Glencross (aggregation support)\n * @author Joachim Skeie (GC MBean support, advanced Deque manipulation)\n * @author KLynch\n */\npublic final class BTraceRuntimeImpl_9 extends BTraceRuntimeImplBase {\n  public static final class Factory extends BTraceRuntimeImplFactory<BTraceRuntimeImpl_9> {\n    public Factory() {\n      super(new BTraceRuntimeImpl_9());\n    }\n\n    @Override\n    public BTraceRuntimeImpl_9 getRuntime(\n        String className, ArgsMap args, CommandListener cmdListener, Instrumentation inst) {\n      return new BTraceRuntimeImpl_9(className, args, cmdListener, inst);\n    }\n\n    @Override\n    public boolean isEnabled() {\n      Runtime.Version version = Runtime.version();\n      int major = version.version().get(0);\n      return major == 9 || major == 10;\n    }\n  }\n  // perf counter variability - we always variable variability\n  private static final int V_Variable = 3;\n  // perf counter units\n  private static final int V_None = 1;\n  private static final int V_String = 5;\n  private static final int PERF_STRING_LIMIT = 256;\n\n  private static Perf perf;\n\n  private final Method findBootstrapOrNullMtd;\n\n  public BTraceRuntimeImpl_9() {\n    fixExports(BTraceRuntime.instrumentation);\n\n    Method m = null;\n    try {\n      m = ClassLoader.class.getDeclaredMethod(\"findBootstrapClassOrNull\", String.class);\n      m.setAccessible(true);\n    } catch (NoSuchMethodException | InaccessibleObjectException ignored) {}\n    findBootstrapOrNullMtd = m;\n  }\n\n  public BTraceRuntimeImpl_9(\n      String className, ArgsMap args, CommandListener cmdListener, Instrumentation inst) {\n    super(className, args, cmdListener, fixExports(inst));\n\n    Method m = null;\n    try {\n      m = ClassLoader.class.getDeclaredMethod(\"findBootstrapClassOrNull\", String.class);\n      m.setAccessible(true);\n    } catch (NoSuchMethodException | InaccessibleObjectException ignored) {}\n    findBootstrapOrNullMtd = m;\n  }\n\n  private static Instrumentation fixExports(Instrumentation instr) {\n    Set<Module> myModules = Collections.singleton(BTraceRuntimeImpl_9.class.getModule());\n    if (instr != null) {\n      instr.redefineModule(\n          String.class.getModule(),\n          Collections.emptySet(),\n          Map.of(\n              \"jdk.internal.reflect\", myModules,\n              \"jdk.internal.perf\", myModules),\n          Collections.singletonMap(\"java.lang\", myModules),\n          Collections.emptySet(),\n          Collections.emptyMap());\n    }\n    return instr;\n  }\n\n  @Override\n  public Class<?> defineClass(byte[] code) {\n    try {\n      // Use StackWalker instead of Reflection.getCallerClass() to avoid\n      // CallerSensitive annotation requirement (only works from bootstrap CL)\n      Class<?> caller =\n          StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)\n              .walk(frames -> frames.skip(1).findFirst())\n              .map(StackWalker.StackFrame::getDeclaringClass)\n              .orElse(null);\n      if (caller == null || !caller.getName().startsWith(\"org.openjdk.btrace.\")) {\n        throw new SecurityException(\"unsafe defineClass\");\n      }\n\n      // Define the probe inside a fresh per-probe anchor class in a new unnamed\n      // ClassLoader. The probe ends up in that loader; once we drop our references\n      // and the HandlerRepository evicts its MethodHandles, the loader becomes\n      // unreachable and the probe class is unloadable.\n      // Pass the ClassLoader that can see BTraceUtils and other agent classes.\n      ClassLoader parent = BTraceRuntimeImpl_9.class.getClassLoader();\n      if (parent == null) {\n        // If BTraceRuntimeImpl_9 is in bootstrap, use the current thread's context CL\n        parent = Thread.currentThread().getContextClassLoader();\n      }\n      Class<?> anchor = ProbeAnchor.defineAnchor(parent);\n      Class<?> clz =\n          MethodHandles.privateLookupIn(anchor, MethodHandles.lookup()).defineClass(code);\n      // initialize the class by creating a dummy instance\n      clz.getConstructor().newInstance();\n      return clz;\n    } catch (IllegalAccessException\n        | NoSuchMethodException\n        | SecurityException\n        | InstantiationException\n        | InvocationTargetException ignored) {\n\n    }\n    return null;\n  }\n\n  /**\n   * Test-only helper: load the provided class bytes into the shared {@code Auxiliary}\n   * loader via {@code privateLookupIn}. Used by instrumentation unit tests that inspect\n   * rewritten probe bytecode alongside the agent's own classes; production probe loading\n   * goes through {@link #defineClass(byte[])} which isolates each probe in its own loader.\n   */\n  public static Class<?> defineClassInAuxiliary(byte[] code) {\n    try {\n      Class<?> clz =\n          MethodHandles.privateLookupIn(Auxiliary.class, MethodHandles.lookup()).defineClass(code);\n      // initialize the class by creating a dummy instance\n      clz.getConstructor().newInstance();\n      return clz;\n    } catch (IllegalAccessException\n        | NoSuchMethodException\n        | SecurityException\n        | InstantiationException\n        | InvocationTargetException ignored) {\n\n    }\n    return null;\n  }\n\n  @Override\n  public void newPerfCounter(Object value, String name, String desc) {\n    Perf perf = getPerf();\n    char tc = desc.charAt(0);\n    switch (tc) {\n      case 'C':\n      case 'Z':\n      case 'B':\n      case 'S':\n      case 'I':\n      case 'J':\n      case 'F':\n      case 'D':\n        {\n          long initValue = (value != null) ? ((Number) value).longValue() : 0L;\n          ByteBuffer b = perf.createLong(name, V_Variable, V_None, initValue);\n          b.order(ByteOrder.nativeOrder());\n          counters.put(name, b);\n        }\n        break;\n\n      case '[':\n        break;\n      case 'L':\n        {\n          if (desc.equals(\"Ljava/lang/String;\")) {\n            byte[] buf;\n            if (value != null) {\n              buf = getStringBytes((String) value);\n            } else {\n              buf = new byte[PERF_STRING_LIMIT];\n              buf[0] = '\\0';\n            }\n            ByteBuffer b = perf.createByteArray(name, V_Variable, V_String, buf, buf.length);\n            counters.put(name, b);\n          }\n        }\n        break;\n    }\n  }\n\n  @Override\n  public ClassLoader getCallerClassLoader(int stackDec) {\n    AtomicInteger cont = new AtomicInteger(stackDec);\n    AtomicReference<ClassLoader> cl = new AtomicReference<>(null);\n    StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)\n        .forEach(\n            f -> {\n              if (f.getClassName().startsWith(\"org.openjdk.btrace.runtime.auxiliary.\")) {\n                return;\n              }\n              if (cont.getAndDecrement() == 0) {\n                cl.compareAndSet(null, f.getDeclaringClass().getClassLoader());\n              }\n            });\n    return cl.get();\n  }\n\n  @Override\n  public Class<?> getCallerClass(int stackDec) {\n    AtomicInteger cont = new AtomicInteger(stackDec);\n    AtomicReference<Class<?>> cl = new AtomicReference<>(null);\n    StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)\n        .forEach(\n            f -> {\n              if (f.getClassName().startsWith(\"org.openjdk.btrace.runtime.auxiliary.\")) {\n                return;\n              }\n              if (cont.getAndDecrement() == 0) {\n                cl.compareAndSet(null, f.getDeclaringClass());\n              }\n            });\n    return cl.get();\n  }\n\n  @Override\n  public int version() {\n    return 9;\n  }\n\n  @Override\n  public JfrEvent.Factory createEventFactory(JfrEvent.Template template) {\n    return () -> JfrEvent.EMPTY;\n  }\n\n  @Override\n  public boolean isBootstrapClass(String className) {\n    try {\n      return findBootstrapOrNullMtd != null\n          && findBootstrapOrNullMtd.invoke(ClassLoader.getSystemClassLoader(), className) != null;\n    } catch (IllegalAccessException | InvocationTargetException ignored) {}\n    return false;\n  }\n\n  private static Perf getPerf() {\n    synchronized (BTraceRuntimeImpl_9.class) {\n      if (perf == null) {\n        perf = AccessController.doPrivileged(new Perf.GetPerfAction());\n      }\n    }\n    return perf;\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/test/java/org/openjdk/btrace/runtime/ExtensionIndyShimIndexTest.java",
    "content": "package org.openjdk.btrace.runtime;\n\nimport org.junit.jupiter.api.Test;\nimport test.shim.ShimService;\n\nimport java.lang.invoke.CallSite;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.MethodType;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass ExtensionIndyShimIndexTest {\n\n  @Test\n  void resolvesNoopShimFromIndex() throws Throwable {\n    MethodHandles.Lookup lk = MethodHandles.lookup();\n    MethodType mt = MethodType.methodType(ShimService.class);\n    // Force fallback path by using a bogus service name; optional=1 and mode=SHIM\n    CallSite cs = ExtensionIndy.bootstrapFieldGet(\n        lk, \"svc\", mt, \"no.such.Service\", \"SIMPLE\", \"\", 1, \"SHIM\");\n    Object o = cs.getTarget().invokeWithArguments();\n    assertNotNull(o, \"Expected shim instance for bogus service in SHIM mode\");\n    assertTrue(o instanceof ShimService, \"Resolved shim is not a ShimService: \" + o.getClass().getName());\n    assertEquals(42, ((ShimService) o).value(), \"Noop shim should return 42\");\n  }\n\n  @Test\n  void resolvesThrowShimFromIndex() throws Throwable {\n    MethodHandles.Lookup lk = MethodHandles.lookup();\n    MethodType mt = MethodType.methodType(ShimService.class);\n    // Force fallback path by using a bogus service name; optional=1 and mode=THROW\n    CallSite cs = ExtensionIndy.bootstrapFieldGet(\n        lk, \"svc\", mt, \"no.such.Service\", \"SIMPLE\", \"\", 1, \"THROW\");\n    ShimService shim = (ShimService) cs.getTarget().invokeWithArguments();\n    assertNotNull(shim, \"Expected shim instance for bogus service in THROW mode\");\n    IllegalStateException ex = assertThrows(IllegalStateException.class, shim::value,\n        \"Expected IllegalStateException when invoking throw-shim\");\n    assertEquals(\"shim-throw\", ex.getMessage(), \"Throw shim message mismatch\");\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/test/java/org/openjdk/btrace/runtime/HiddenClassDefineRegressionTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n */\n\npackage org.openjdk.btrace.runtime;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assumptions.assumeTrue;\n\nimport java.lang.invoke.MethodHandles;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Method;\n\nimport org.junit.jupiter.api.Test;\nimport org.openjdk.btrace.runtime.auxiliary.Auxiliary;\n\n/** Regression tests for the hidden-class probe defineClass path on JDK 15+. */\nclass HiddenClassDefineRegressionTest {\n\n  @Test\n  void auxiliaryLookupHasFullPrivilegeAccess() throws Exception {\n    MethodHandles.Lookup lookup = Auxiliary.lookup();\n    assertEquals(Auxiliary.class, lookup.lookupClass(),\n        \"lookup must be anchored on Auxiliary\");\n    // hasFullPrivilegeAccess is JDK 14+; reflect so this test source set stays\n    // compilable against older targets.\n    Method hasFullPriv;\n    try {\n      hasFullPriv = MethodHandles.Lookup.class.getMethod(\"hasFullPrivilegeAccess\");\n    } catch (NoSuchMethodException tooOld) {\n      return;\n    }\n    assertTrue((Boolean) hasFullPriv.invoke(lookup),\n        \"Auxiliary.lookup() must grant PRIVATE|MODULE (defineHiddenClass precondition)\");\n  }\n\n  @Test\n  void defineHiddenClassWithAuxiliaryLookupSucceeds() throws Throwable {\n    assumeTrue(Runtime.version().feature() >= 15, \"defineHiddenClass is JDK 15+\");\n\n    String internalName = Auxiliary.class.getPackage().getName().replace('.', '/')\n        + \"/HiddenClassProbe$Test\";\n    byte[] bytes = ProbeAnchor.generateAnchorBytes(internalName);\n\n    MethodHandles.Lookup lookup = Auxiliary.lookup();\n    Class<?> classOptionClass =\n        Class.forName(\"java.lang.invoke.MethodHandles$Lookup$ClassOption\");\n    Object emptyOptions = Array.newInstance(classOptionClass, 0);\n    Method defineHidden = MethodHandles.Lookup.class.getMethod(\n        \"defineHiddenClass\", byte[].class, boolean.class, emptyOptions.getClass());\n    Object hiddenLookup = defineHidden.invoke(lookup, bytes, true, emptyOptions);\n    Method lookupClassMtd = hiddenLookup.getClass().getMethod(\"lookupClass\");\n    Class<?> defined = (Class<?>) lookupClassMtd.invoke(hiddenLookup);\n\n    assertNotNull(defined, \"defineHiddenClass returned null\");\n    assertTrue(defined.isHidden(), \"expected a hidden class\");\n    assertTrue(defined.getName().startsWith(internalName.replace('/', '.')),\n        \"hidden class name should start with declared name: \" + defined.getName());\n  }\n\n  @Test\n  void hiddenClassNameIsStrippedForRuntimeLookup() {\n    String plain = \"org.openjdk.btrace.runtime.auxiliary.SampleProbe\";\n    String hidden = plain + \"/0x00000007ff0abcd0\";\n    assertEquals(plain, BTraceRuntimeAccessImpl.normalizeProbeName(hidden));\n    assertEquals(plain, BTraceRuntimeAccessImpl.normalizeProbeName(plain));\n  }\n}\n"
  },
  {
    "path": "btrace-runtime/src/test/java/test/shim/ShimService.java",
    "content": "package test.shim;\n\npublic interface ShimService {\n  int value();\n}\n\n"
  },
  {
    "path": "btrace-runtime/src/test/java/test/shim/ShimServiceNoop.java",
    "content": "package test.shim;\n\npublic final class ShimServiceNoop implements ShimService {\n  public static final ShimServiceNoop INSTANCE = new ShimServiceNoop();\n  private ShimServiceNoop() {}\n\n  @Override\n  public int value() { return 42; }\n}\n\n"
  },
  {
    "path": "btrace-runtime/src/test/java/test/shim/ShimServiceThrow.java",
    "content": "package test.shim;\n\npublic final class ShimServiceThrow implements ShimService {\n  public static final ShimServiceThrow INSTANCE = new ShimServiceThrow();\n  private ShimServiceThrow() {}\n\n  @Override\n  public int value() { throw new IllegalStateException(\"shim-throw\"); }\n}\n\n"
  },
  {
    "path": "btrace-runtime/src/test/resources/META-INF/btrace/shims.index",
    "content": "test.shim.ShimService=test.shim.ShimServiceNoop,test.shim.ShimServiceThrow\n\n"
  },
  {
    "path": "btrace-ui/build.gradle",
    "content": "import java.text.SimpleDateFormat\nimport java.util.Date\n\nbuildscript { scriptHandler ->\n    apply from: rootProject.file('buildSrc/shared.gradle'), to: scriptHandler\n}\n\nsourceCompatibility = '11'\ntargetCompatibility = '11'\n\ndependencies {\n    implementation project(':btrace-core')\n    implementation project(':btrace-compiler')\n    implementation project(':btrace-instr')\n}\n\njar {\n    manifest {\n        attributes(\n                'Built-By'       : System.properties['user.name'],\n                'Build-Timestamp': new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss.SSSZ\").format(new Date()),\n                'Build-Revision' : getGitCommit(),\n                'Created-By'     : \"Gradle ${gradle.gradleVersion}\",\n                'Build-Jdk'      : \"${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']})\",\n                'Build-OS'       : \"${System.properties['os.name']} ${System.properties['os.arch']} ${System.properties['os.version']}\",\n                'Main-Class'     : \"org.openjdk.btrace.client.Main\"\n        )\n    }\n}\n"
  },
  {
    "path": "build.gradle",
    "content": "plugins {\n    id \"jacoco\"\n    alias(libs.plugins.spotless)\n    alias(libs.plugins.publish)\n}\n\n// Applied to the root project AND every subproject. The root project needs group/version\n// so the nexus-publish plugin can resolve its packageGroup (defaults to rootProject.group)\n// and so the SNAPSHOT-skip guard below evaluates against a real version.\nallprojects {\n    group = 'org.openjdk.btrace'\n    version = '3.0.0-SNAPSHOT'\n}\n\nrepositories {\n    mavenCentral()\n}\n\nsubprojects {\n    apply from: rootProject.file('common.gradle')\n}\n\ntask mergedJavadoc(type: Javadoc, description: 'Creates Javadoc from all the projects.') {\n    title = 'All modules'\n    destinationDir = new File(project.buildDir, 'merged-javadoc')\n\n    // Note: The closures below are executed lazily.\n    source {\n        subprojects*.sourceSets*.main*.allSource\n    }\n    classpath.from {\n        subprojects*.configurations*.compile*.copyRecursive({ !(it instanceof ProjectDependency) })*.resolve()\n    }\n}\n\nspotless {\n    java {\n        target 'src/*/java/**/*.java'\n        // note: you can use an empty string for all the imports you didn't specify explicitly, and '\\\\#` prefix for static imports\n        importOrder('java', 'javax', 'org.openjdk.btrace', '', '\\\\#org.openjdk.btrace', '\\\\#')\n        removeUnusedImports()\n\n        googleJavaFormat()   // has its own section below\n\n        formatAnnotations()  // fixes formatting of type annotations, see below\n\n        licenseHeader '/* (C) $YEAR */' // or licenseHeaderFile\n    }\n}\n\n// Nexus Publishing configuration for Maven Central release automation\n// This enables the closeAndReleaseStagingRepositories task for automated releases\n// Uses the new Central Portal URLs (OSSRH was sunset on June 30, 2025)\nnexusPublishing {\n    repositories {\n        sonatype {\n            nexusUrl.set(uri(\"https://ossrh-staging-api.central.sonatype.com/service/local/\"))\n            snapshotRepositoryUrl.set(uri(\"https://central.sonatype.com/repository/maven-snapshots/\"))\n            // Use Central Portal user token credentials (different from legacy OSSRH credentials)\n            username = findProperty(\"sonatype.user\")\n                    ?: findProperty(\"sonatype.username\")\n                    ?: System.getenv(\"SONATYPE_USER\")\n                    ?: System.getenv(\"SONATYPE_USERNAME\")\n            password = findProperty(\"sonatype.password\")\n                    ?: System.getenv(\"SONATYPE_PASSWORD\")\n        }\n    }\n}\n\ndef sonatypeUsername = findProperty(\"sonatype.user\")\n        ?: findProperty(\"sonatype.username\")\n        ?: System.getenv(\"SONATYPE_USER\")\n        ?: System.getenv(\"SONATYPE_USERNAME\")\ndef sonatypePassword = findProperty(\"sonatype.password\")\n        ?: System.getenv(\"SONATYPE_PASSWORD\")\ndef hasSonatypeCredentials =\n        sonatypeUsername != null && !sonatypeUsername.toString().trim().isEmpty()\n                && sonatypePassword != null\n                && !sonatypePassword.toString().trim().isEmpty()\n\nif (!hasSonatypeCredentials || project.version.endsWith(\"-SNAPSHOT\")) {\n    logger.lifecycle(\"Sonatype credentials not provided or running with snapshot; skipping Nexus staging initialization and release tasks.\")\n    def skipTheseTasks = [\n        \"initializeSonatypeStagingRepository\",\n        \"publishToSonatype\",\n        \"closeSonatypeStagingRepository\",\n        \"dropSonatypeStagingRepository\",\n        \"releaseSonatypeStagingRepository\",\n    ]\n    tasks.matching { skipTheseTasks.contains(it.name) }.configureEach {\n        enabled = false\n    }\n}\n"
  },
  {
    "path": "buildSrc/build.gradle",
    "content": "// Intentionally left minimal.\n"
  },
  {
    "path": "buildSrc/shared.gradle",
    "content": "configurations.all {\n    resolutionStrategy.eachDependency { details ->\n        if (details.requested.group == 'org.ajoberstar.grgit' &&\n                details.requested.name == 'grgit-core' &&\n                details.requested.version == '4.0.1') {\n            details.useVersion '4.1.1'\n            details.because '4.0.1 has been removed'\n        }\n    }\n}\n"
  },
  {
    "path": "common.gradle",
    "content": "//\n// This file is to be applied to every subproject.\n//\n\napply plugin: 'java'\napply plugin: 'idea'\n\n// group and version are set on all projects (including root) via the allprojects\n// block in the root build.gradle. Duplicating them here would drift during releases\n// (the release workflow only updates build.gradle).\n\nbuildscript {\n    repositories {\n        mavenCentral()\n    }\n}\n\next.getToolsJar = {\n    // Prefer a JDK 8 tools.jar, which contains com.sun.tools.attach, com.sun.source.*, and sun.jvmstat.*\n    try {\n        def jdk8 = javaToolchains.compilerFor { languageVersion.set(JavaLanguageVersion.of(8)) }.get()\n        def tj = jdk8.metadata.installationPath.file(\"lib/tools.jar\")\n        return tj\n    } catch (Throwable ignore) {\n        // Fallback to empty file reference to avoid NPEs; callers should check existence\n        return file('non-existent-tools.jar')\n    }\n}\n\next.getJavac = { int version = 11 ->\n    return javaToolchains.compilerFor {\n        languageVersion.set(JavaLanguageVersion.of(version))\n    }.get().metadata.installationPath.file(\"bin/javac\")\n}\n\next.getJavadoc = {\n    return javaToolchains.compilerFor {\n        languageVersion.set(JavaLanguageVersion.of(8))\n    }.get().metadata.installationPath.file(\"bin/javadoc\")\n}\n\next.getGitCommit = {\n    try {\n        def stdout = new ByteArrayOutputStream()\n        exec {\n            commandLine 'git', 'rev-parse', 'HEAD'\n            standardOutput = stdout\n            ignoreExitValue = true\n        }\n        def commit = stdout.toString().trim()\n        return commit ?: 'dev'\n    } catch (Exception e) {\n        return 'dev'\n    }\n}\n\n[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'\n\ncompileJava {\n    sourceCompatibility = 8\n    targetCompatibility = 8\n    javaCompiler = javaToolchains.compilerFor {\n        languageVersion.set(JavaLanguageVersion.of(11))\n    }\n}\n\nrepositories {\n    mavenCentral()\n    // You may define additional repositories, or even remove \"mavenCentral()\".\n    // Read more about repositories here:\n    //   http://www.gradle.org/docs/current/userguide/dependency_management.html#sec:repositories\n}\n\ndependencies {\n    // Adding dependencies here will add the dependencies to each subproject.\n\ttestImplementation libs.junit.jupiter\n}\n\nString mavenArtifactId = name\n\njavadoc {\n    options.addStringOption('Xdoclint:all,-missing', '-quiet')\n    options.encoding(\"UTF-8\")\n    executable = \"${getJavadoc()}\"\n    failOnError true\n    // Ensure Javadoc can resolve com.sun.* APIs (tools.jar on JDK8)\n    doFirst {\n        def toolsJar = getToolsJar()\n        try {\n            File tj = (toolsJar instanceof File) ? toolsJar : toolsJar?.asFile\n            if (tj != null && tj.exists()) {\n                classpath += files(tj)\n            }\n        } catch (Throwable ignore) {\n            // Ignore if toolchain lacks tools.jar (JDK9+); compile still uses modules\n        }\n    }\n}\n\ntask sourcesJar(type: Jar, dependsOn: classes, description: 'Creates a jar from the source files.') {\n    archiveClassifier = 'sources'\n    from sourceSets.main.allSource\n}\n\ntask javadocJar(type: Jar, dependsOn: javadoc) {\n    archiveClassifier = 'javadoc'\n    from javadoc.destinationDir\n}\n\nartifacts {\n    archives jar\n    archives sourcesJar\n    archives javadocJar\n}\n\ntask createFolders(description: 'Creates the source folders if they do not exist.') doLast {\n    sourceSets*.allSource*.srcDirs*.each { File srcDir ->\n        if (!srcDir.isDirectory()) {\n            println \"Creating source folder: ${srcDir}\"\n            srcDir.mkdirs()\n        }\n    }\n}\n\ntest {\n    useJUnitPlatform()\n    // Always run tests, even when nothing changed.\n    dependsOn 'cleanTest'\n\n    // Show test results.\n    testLogging {\n        events \"passed\", \"skipped\", \"failed\"\n    }\n}\n"
  },
  {
    "path": "doc/specs/2026-04-11-btraceiobtrace802-phase-3-invokedynamic-handler-isolation.md",
    "content": "---\nspec_id: REQ-btraceio-btrace-802\nsource: github\nsource_ref: \"btraceio/btrace#802\"\ntitle: \"Phase 3: INVOKEDYNAMIC handler isolation\"\nstatus: implementing\nclarity_score: 82\ncreated: 2026-04-11\nimplementing_session: impl-1775895298\nimplemented_pr: null\n---\n\n# Phase 3: INVOKEDYNAMIC handler isolation\n\nReplace INVOKESTATIC handler copying with INVOKEDYNAMIC dispatch. Probe handler methods now stay in the probe class (bootstrap CL) and are called via ConstantCallSite, eliminating bytecode copying into target classes. IndyDispatcher must work from Java 8+.\n\nNew files: IndyDispatcher, HandlerRepository (interface), HandlerRepositoryImpl, DispatchBenchmark, DispatchTarget, Workload, DispatchScript\nDeleted: CopyingVisitor, Indy, ~400 redundant golden files (replaced with unified golden files covering all combinations)\nRefactored: Instrumentor, Assembler, BTraceProbeNode, BTraceProbePersisted, BTraceRuntimeImpl_9/_11\n\nDispatch chain: InstrumentedMethod → INVOKEDYNAMIC → IndyDispatcher.bootstrap() → HandlerRepositoryImpl.resolveHandler() → MethodHandles.publicLookup().findStatic() → ConstantCallSite\n\nIntegration fixes:\n1. AnyType descriptor transformation in BTraceProbeNode.getBytecode() and BTraceProbePersisted.register() — Lorg/openjdk/btrace/core/types/AnyType; → Ljava/lang/Object;\n2. StackWalker auxiliary frame skipping in BTraceRuntimeImpl_9/_11 for getCallerClassLoader() and getCallerClass()\n3. HandlerRepositoryImpl cleanup: use ConcurrentHashMap with sentinel value for failed lookups instead of null; clean findStatic lookup with warn-on-failure\n\nReview fixes:\n- Symmetric probe lifecycle: unregisterProbe() in both BTraceProbeNode.unregister() and BTraceProbePersisted.unregister(); removed premature registerProbe from BTraceProbeFactory.createProbe()\n- COMPUTE_FRAMES=0 in transformAnyTypeDescriptors() (only descriptor changes, no control flow)\n- Remove redundant unregisterProbe from Client.onExit()\n\nTest plan:\n- gradlew :btrace-instr:test — all instrumentor tests pass\n- gradlew :integration-tests:test -Pintegration — all 22 integration tests pass (including Docker)\n- gradlew :benchmarks:runtime-benchmarks:jmh -PjmhInclude=DispatchBenchmark — benchmarks stable\n- Automated test: verify attach/detach cycle cleans up all handler cache entries in HandlerRepositoryImpl\n\n## Acceptance Criteria\n\n- [ ] IndyDispatcher works from Java 8+\n- [ ] All ~400 redundant golden files are replaced with unified golden files that cover all probe type combinations\n- [ ] Automated test verifies attach/detach cycle cleans up all handler cache entries in HandlerRepositoryImpl\n- [ ] HandlerRepositoryImpl uses ConcurrentHashMap with sentinel value for failed lookups instead of null\n- [ ] All 22 integration tests pass\n- [ ] All instrumentor tests pass\n- [ ] DispatchBenchmark benchmarks remain stable\n"
  },
  {
    "path": "docker/.dockerignore",
    "content": "# Exclude files not needed in Docker build context to optimize build speed\n\n# Samples (optional - can be excluded to reduce image size)\n# Uncomment the line below to exclude samples from the image\n# btrace/samples/\n\n# Windows batch files (not needed in Linux containers)\nbtrace/bin/*.bat\n\n# Documentation files\nbtrace/*.txt\nbtrace/LICENSE*\nbtrace/COPYRIGHT\n\n# Native libraries for other architectures (optional)\n# Keep only what's needed for the target platform\n"
  },
  {
    "path": "docker/Dockerfile",
    "content": "# BTrace Docker Image - Debian-based variant\n# Full distribution with all tools and shell access\nFROM bellsoft/liberica-openjdk-debian:11.0.30-cds\n\nARG BTRACE_VERSION=2.3.0-SNAPSHOT\n\nLABEL maintainer=\"BTrace Project <https://github.com/btraceio/btrace>\" \\\n      org.opencontainers.image.title=\"BTrace\" \\\n      org.opencontainers.image.description=\"Safe, dynamic tracing tool for the Java platform\" \\\n      org.opencontainers.image.url=\"https://github.com/btraceio/btrace\" \\\n      org.opencontainers.image.source=\"https://github.com/btraceio/btrace\" \\\n      org.opencontainers.image.version=\"${BTRACE_VERSION}\" \\\n      org.opencontainers.image.licenses=\"GPL-2.0-only WITH Classpath-exception-2.0\"\n\n# Install required tools\nRUN apt-get update && \\\n    apt-get install -y --no-install-recommends \\\n        procps \\\n        curl \\\n        ca-certificates && \\\n    rm -rf /var/lib/apt/lists/*\n\n# Create BTrace installation directory\nRUN mkdir -p /opt/btrace\n\n# Copy BTrace distribution\nCOPY btrace/ /opt/btrace/\n\n# Set ownership and permissions\nRUN chmod -R 755 /opt/btrace/bin && \\\n    chmod 644 /opt/btrace/libs/*.jar\n\n# Set environment variables\nENV BTRACE_HOME=/opt/btrace \\\n    PATH=\"${PATH}:/opt/btrace/bin\" \\\n    JAVA_HOME=/usr/local/openjdk-11\n\n# Verify installation\nRUN btrace --version || echo \"BTrace installed\"\n\n# Add entrypoint script\nCOPY docker-entrypoint.sh /usr/local/bin/\nRUN chmod +x /usr/local/bin/docker-entrypoint.sh\n\nWORKDIR /work\n\nENTRYPOINT [\"/usr/local/bin/docker-entrypoint.sh\"]\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "docker/Dockerfile.alpine",
    "content": "# BTrace Docker Image - Alpine variant\n# Smaller footprint for Kubernetes sidecars and resource-constrained environments\nFROM alpine:3.23\n\nARG BTRACE_VERSION=2.3.0-SNAPSHOT\n\nLABEL maintainer=\"BTrace Project <https://github.com/btraceio/btrace>\" \\\n      org.opencontainers.image.title=\"BTrace Alpine\" \\\n      org.opencontainers.image.description=\"Safe, dynamic tracing tool for the Java platform (Alpine variant)\" \\\n      org.opencontainers.image.url=\"https://github.com/btraceio/btrace\" \\\n      org.opencontainers.image.source=\"https://github.com/btraceio/btrace\" \\\n      org.opencontainers.image.version=\"${BTRACE_VERSION}\" \\\n      org.opencontainers.image.licenses=\"GPL-2.0-only WITH Classpath-exception-2.0\"\n\n# Install OpenJDK 11 and required tools\nRUN apk add --no-cache \\\n        openjdk11-jdk \\\n        bash \\\n        procps \\\n        curl \\\n        ca-certificates\n\n# Create BTrace installation directory\nRUN mkdir -p /opt/btrace\n\n# Copy BTrace distribution\nCOPY btrace/ /opt/btrace/\n\n# Set ownership and permissions\nRUN chmod -R 755 /opt/btrace/bin && \\\n    chmod 644 /opt/btrace/libs/*.jar\n\n# Set environment variables\nENV BTRACE_HOME=/opt/btrace \\\n    PATH=\"${PATH}:/opt/btrace/bin\" \\\n    JAVA_HOME=/usr/lib/jvm/java-11-openjdk\n\n# Verify installation\nRUN btrace --version || echo \"BTrace installed\"\n\n# Add entrypoint script\nCOPY docker-entrypoint.sh /usr/local/bin/\nRUN chmod +x /usr/local/bin/docker-entrypoint.sh\n\nWORKDIR /work\n\nENTRYPOINT [\"/usr/local/bin/docker-entrypoint.sh\"]\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "docker/Dockerfile.distroless",
    "content": "# BTrace Docker Image - Distroless variant\n# Minimal attack surface for production use with BTrace agent\n# Runtime JARs only, no shell or unnecessary tools\nFROM gcr.io/distroless/java11-debian11\n\nARG BTRACE_VERSION=2.3.0-SNAPSHOT\n\nLABEL maintainer=\"BTrace Project <https://github.com/btraceio/btrace>\" \\\n      org.opencontainers.image.title=\"BTrace Distroless\" \\\n      org.opencontainers.image.description=\"Safe, dynamic tracing tool for the Java platform (Distroless variant)\" \\\n      org.opencontainers.image.url=\"https://github.com/btraceio/btrace\" \\\n      org.opencontainers.image.source=\"https://github.com/btraceio/btrace\" \\\n      org.opencontainers.image.version=\"${BTRACE_VERSION}\" \\\n      org.opencontainers.image.licenses=\"GPL-2.0-only WITH Classpath-exception-2.0\"\n\n# Copy only BTrace runtime libraries (no shell scripts since distroless has no shell)\nCOPY btrace/libs /opt/btrace/libs\n\n# Note: Distroless images don't support environment variables in the traditional way\n# Users should specify paths directly in their java command\n# Example: java -javaagent:/opt/btrace/libs/btrace-agent.jar=...\n\nWORKDIR /work\n"
  },
  {
    "path": "docker/README.md",
    "content": "# BTrace Docker Images\n\nOfficial Docker images for [BTrace](https://github.com/btraceio/btrace) - a safe, dynamic tracing tool for the Java platform.\n\n## Quick Start\n\n```dockerfile\n# Copy BTrace into your application image\nFROM btrace/btrace:2.3.0 AS btrace\nFROM bellsoft/liberica-openjdk-debian:11-cds\n\nCOPY --from=btrace /opt/btrace /opt/btrace\nENV BTRACE_HOME=/opt/btrace PATH=\"${PATH}:/opt/btrace/bin\"\n\n# Your application...\n```\n\n## Image Variants\n\n### `btrace/btrace:latest` (~25MB)\n**Debian-based** - Full distribution with all tools and shell access\n\n- **Base:** OpenJDK 11 JDK on Debian Slim\n- **Use case:** General purpose, development, interactive debugging\n- **Includes:** Complete BTrace toolchain, shell access, samples\n- **Best for:** Development environments, interactive troubleshooting\n\n```dockerfile\nFROM btrace/btrace:2.3.0\n```\n\n### `btrace/btrace:latest-alpine` (~15MB)\n**Alpine-based** - Smaller footprint for cloud environments\n\n- **Base:** Alpine Linux with OpenJDK 11\n- **Use case:** Kubernetes sidecars, resource-constrained environments\n- **Includes:** Complete BTrace toolchain, smaller base OS\n- **Best for:** Production sidecars, cloud deployments\n\n```dockerfile\nFROM btrace/btrace:2.3.0-alpine\n```\n\n### `btrace/btrace:latest-distroless` (~10MB)\n**Distroless** - Minimal attack surface for security-focused deployments\n\n- **Base:** Google Distroless Java 11\n- **Use case:** Production agent mode, minimal security surface\n- **Includes:** BTrace runtime JARs only (no shell, no scripts)\n- **Best for:** Production applications using `-javaagent`\n\n```dockerfile\nFROM btrace/btrace:2.3.0-distroless AS btrace\nFROM gcr.io/distroless/java11\nCOPY --from=btrace /opt/btrace/libs /opt/btrace/libs\n```\n\n## Usage Patterns\n\n### Pattern 1: Multi-Stage Build\n\nMost common - copy BTrace into your application image:\n\n```dockerfile\nFROM btrace/btrace:2.3.0 AS btrace\nFROM bellsoft/liberica-openjdk-debian:11-cds\nWORKDIR /app\n\nCOPY target/myapp.jar /app/\nCOPY --from=btrace /opt/btrace /opt/btrace\n\nENV BTRACE_HOME=/opt/btrace\nENV PATH=\"${PATH}:${BTRACE_HOME}/bin\"\n\nENTRYPOINT [\"java\", \"-jar\", \"myapp.jar\"]\n```\n\n**Usage:**\n```bash\ndocker build -t myapp:latest .\ndocker run -d --name myapp myapp:latest\ndocker exec myapp btrace <PID> /scripts/trace.btrace\n```\n\n### Pattern 2: Kubernetes Sidecar\n\nRun BTrace as a sidecar container:\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: myapp-with-btrace\nspec:\n  shareProcessNamespace: true  # Required!\n  containers:\n  - name: myapp\n    image: myapp:latest\n\n  - name: btrace-sidecar\n    image: btrace/btrace:2.3.0-alpine\n    command: [\"/bin/sh\", \"-c\", \"while true; do sleep 30; done\"]\n    volumeMounts:\n    - name: btrace-scripts\n      mountPath: /scripts\n\n  volumes:\n  - name: btrace-scripts\n    configMap:\n      name: btrace-scripts\n```\n\n**Usage:**\n```bash\nkubectl exec myapp-with-btrace -c btrace-sidecar -- \\\n  sh -c 'btrace $(pgrep -f myapp) /scripts/trace.btrace'\n```\n\n### Pattern 3: Development Image\n\nExtend BTrace image for development:\n\n```dockerfile\nFROM btrace/btrace:2.3.0-alpine\n\nCOPY target/myapp.jar /app/myapp.jar\nCOPY scripts/*.btrace /scripts/\n\nENTRYPOINT [\"btracer\"]\nCMD [\"-v\", \"-o\", \"/tmp/btrace-output.txt\", \"/app/myapp.jar\"]\n```\n\n### Pattern 4: Distroless Production\n\nMinimal image with BTrace agent:\n\n```dockerfile\nFROM btrace/btrace:2.3.0-distroless AS btrace\nFROM gcr.io/distroless/java11\nWORKDIR /app\n\nCOPY --from=build /app/target/myapp.jar /app/\nCOPY --from=btrace /opt/btrace/libs /opt/btrace/libs\n\nENTRYPOINT [\"java\", \\\n  \"-javaagent:/opt/btrace/libs/btrace-agent.jar=script=/scripts/trace.btrace\", \\\n  \"-Xbootclasspath/a:/opt/btrace/libs/btrace-boot.jar\", \\\n  \"-jar\", \"/app/myapp.jar\"]\n```\n\n### Pattern 5: Docker Compose\n\nLocal development with BTrace:\n\n```yaml\nversion: '3.8'\nservices:\n  myapp:\n    image: myapp:latest\n    ports:\n      - \"8080:8080\"\n\n  btrace:\n    image: btrace/btrace:2.3.0-alpine\n    network_mode: \"service:myapp\"\n    pid: \"service:myapp\"\n    volumes:\n      - ./scripts:/scripts\n      - ./output:/output\n    command: >\n      sh -c 'sleep 5; btrace $(pgrep -f myapp) /scripts/trace.btrace'\n```\n\n## Image Selection Guide\n\n| Variant | Size | Shell | Scripts | Use Case |\n|---------|------|-------|---------|----------|\n| **latest** | ~25MB | ✓ | ✓ | Development, debugging |\n| **alpine** | ~15MB | ✓ | ✓ | Kubernetes sidecar |\n| **distroless** | ~10MB | ✗ | ✗ | Production agent mode |\n\n**Recommendations:**\n- **Development:** Use `btrace:latest` for full tooling\n- **Kubernetes Sidecar:** Use `btrace:latest-alpine` for size efficiency\n- **Production Agent:** Use `btrace:latest-distroless` for security\n\n## Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `BTRACE_HOME` | `/opt/btrace` | BTrace installation directory |\n| `BTRACE_OPTS` | (empty) | Additional BTrace command options |\n| `JAVA_HOME` | (auto-detected) | Java installation path |\n| `BTRACE_VERBOSE` | `false` | Print version info on startup |\n\n## Scenarios\n\n### Troubleshoot Production Issue\n\n```bash\n# Copy script into container\ndocker cp troubleshoot.btrace myapp:/tmp/\n\n# Find Java process PID\ndocker exec myapp jps -l\n\n# Attach BTrace\ndocker exec myapp btrace <PID> /tmp/troubleshoot.btrace\n\n# View output\ndocker exec myapp cat /tmp/btrace-output.txt\n```\n\n### Continuous Monitoring in Kubernetes\n\n```bash\n# Deploy scripts as ConfigMap\nkubectl create configmap btrace-scripts \\\n  --from-file=monitor.btrace=./scripts/monitor.btrace\n\n# Deploy application with sidecar\nkubectl apply -f app-with-btrace-sidecar.yaml\n\n# Stream output\nkubectl logs -f myapp-pod -c btrace-sidecar\n\n# Update script without restart\nkubectl create configmap btrace-scripts \\\n  --from-file=monitor.btrace=./scripts/updated.btrace \\\n  --dry-run=client -o yaml | kubectl apply -f -\n```\n\n### Performance Profiling\n\n```dockerfile\nFROM btrace/btrace:2.3.0 AS btrace\nFROM bellsoft/liberica-openjdk-debian:11-cds\n\nCOPY --from=btrace /opt/btrace /opt/btrace\nENV BTRACE_HOME=/opt/btrace PATH=\"${PATH}:${BTRACE_HOME}/bin\"\n\nCOPY target/myapp.jar /app/\nCOPY scripts/profile-*.btrace /scripts/\n\nENTRYPOINT [\"btracer\", \\\n  \"-v\", \"-o\", \"/tmp/profile.txt\", \\\n  \"/scripts/profile-methods.btrace\", \\\n  \"-jar\", \"/app/myapp.jar\"]\n```\n\n## Best Practices\n\n1. **Use specific version tags in production:**\n   ```dockerfile\n   FROM btrace/btrace:2.3.0  # Good\n   FROM btrace/btrace:latest  # Avoid in production\n   ```\n\n2. **Multi-stage builds minimize size:**\n   ```dockerfile\n   FROM btrace/btrace:2.3.0 AS btrace\n   FROM your-app-image\n   COPY --from=btrace /opt/btrace /opt/btrace\n   ```\n\n3. **Enable process namespace sharing in Kubernetes:**\n   ```yaml\n   spec:\n     shareProcessNamespace: true  # Required!\n   ```\n\n4. **Store scripts in ConfigMaps:**\n   ```bash\n   kubectl create configmap btrace-scripts --from-file=./scripts/\n   ```\n\n5. **Use appropriate security contexts:**\n   ```yaml\n   securityContext:\n     runAsNonRoot: true\n     readOnlyRootFilesystem: true\n     capabilities:\n       drop: [\"ALL\"]\n       add: [\"SYS_PTRACE\"]  # Required\n   ```\n\n6. **Monitor BTrace overhead:**\n   - Start with minimal instrumentation\n   - Test in staging first\n   - Use sampling for high-frequency events\n\n## Troubleshooting\n\n### \"Cannot attach to process\"\n```bash\n# Ensure process namespace sharing\ndocker run --pid=container:target-container btrace/btrace:latest\n\n# Kubernetes: verify shareProcessNamespace\nkubectl get pod myapp -o yaml | grep shareProcessNamespace\n```\n\n### \"BTRACE_HOME not found\"\n```bash\n# Verify installation\ndocker exec myapp ls -la $BTRACE_HOME\ndocker exec myapp env | grep BTRACE\n```\n\n### \"Java tools not available\"\n```bash\n# Ensure JDK (not JRE) is installed\ndocker exec myapp java -version\ndocker exec myapp which javac\n\n# Java 9+ requires module exports\nENV JAVA_OPTS=\"--add-exports jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"\n```\n\n## Building Images Locally\n\n```bash\n# Build BTrace distribution first\n./gradlew :btrace-dist:build\n\n# Build Docker images\n./gradlew :btrace-dist:buildDockerImages\n\n# Or build manually\nVERSION=2.3.0-SNAPSHOT  # Set this to your BTrace version\ncd docker\ndocker build -t btrace/btrace:local -f Dockerfile ../btrace-dist/build/resources/main/v${VERSION}\ndocker build -t btrace/btrace:local-alpine -f Dockerfile.alpine ../btrace-dist/build/resources/main/v${VERSION}\ndocker build -t btrace/btrace:local-distroless -f Dockerfile.distroless ../btrace-dist/build/resources/main/v${VERSION}\n```\n\n## Supported Platforms\n\n- **linux/amd64** - Intel/AMD 64-bit (all variants)\n- **linux/arm64** - ARM 64-bit (all variants)\n\nNote: Native DTrace library (`libbtrace.so`) is x86-only. DTrace features are not available on ARM platforms.\n\n## License\n\nBTrace is licensed under GPL-2.0-only WITH Classpath-exception-2.0.\n\n## Links\n\n- **GitHub:** https://github.com/btraceio/btrace\n- **Documentation:** https://github.com/btraceio/btrace/tree/develop/docs\n- **Issues:** https://github.com/btraceio/btrace/issues\n- **Docker Hub:** https://hub.docker.com/r/btrace/btrace\n\n## Support\n\nFor questions and support:\n- GitHub Issues: https://github.com/btraceio/btrace/issues\n- Documentation: https://github.com/btraceio/btrace/tree/develop/docs\n"
  },
  {
    "path": "docker/docker-entrypoint.sh",
    "content": "#!/bin/bash\nset -e\n\n# BTrace Docker Entrypoint Script\n# Initializes environment and runs BTrace commands\n\n# Print version information if verbose\nif [ \"${BTRACE_VERBOSE:-false}\" = \"true\" ]; then\n    echo \"BTrace Docker Image\"\n    echo \"BTRACE_HOME: ${BTRACE_HOME:-/opt/btrace}\"\n    echo \"JAVA_HOME: ${JAVA_HOME}\"\n    java -version\nfi\n\n# Validate Java installation\nif ! command -v java &> /dev/null; then\n    echo \"ERROR: Java not found in PATH\"\n    exit 1\nfi\n\n# Initialize BTRACE_HOME if not set\nif [ -z \"$BTRACE_HOME\" ]; then\n    export BTRACE_HOME=/opt/btrace\nfi\n\n# Verify BTrace installation\nif [ ! -d \"$BTRACE_HOME\" ]; then\n    echo \"ERROR: BTRACE_HOME directory not found: $BTRACE_HOME\"\n    exit 1\nfi\n\n# Add BTrace bin to PATH if not already there\ncase \":$PATH:\" in\n    *\":$BTRACE_HOME/bin:\"*)\n        # already in PATH, do nothing\n        ;;\n    *)\n        export PATH=\"$PATH:$BTRACE_HOME/bin\"\n        ;;\nesac\n\n# If first argument is a btrace command, execute it directly\nif [ \"${1#-}\" != \"$1\" ] || [ \"$1\" = \"btrace\" ] || [ \"$1\" = \"btracer\" ] || [ \"$1\" = \"btracec\" ] || [ \"$1\" = \"btracep\" ]; then\n    exec \"$@\"\nfi\n\n# If first argument is a shell or starts with /, execute as-is\nif [ \"$1\" = \"/bin/bash\" ] || [ \"$1\" = \"/bin/sh\" ]; then\n    exec \"$@\"\nelse\n    case \"$1\" in\n        /*)\n            exec \"$@\"\n            ;;\n    esac\nfi\n\n# Default: execute the provided command\nexec \"$@\"\n"
  },
  {
    "path": "docs/BTraceExtensionDevelopmentGuide.md",
    "content": "# BTrace Extension Development Guide\n\n## Overview\n\nBTrace extensions provide reusable services that can be injected into BTrace scripts. This guide covers the recommended, plugin-based workflow using a single Gradle module with two source sets (`api`, `impl`). The plugin separates artifacts, generates metadata, shades implementation dependencies, and prepares distributables.\n\nFor API authoring rules that the build verifies, see `docs/ExtensionInterfaceRules.md`.\n\n## Architecture\n\n### Classloader Isolation\n\nExtensions are isolated while exposing only their API to scripts:\n\n```\nBootstrap ClassLoader\n├── JRE classes\n├── btrace-boot.jar (BTrace core + extension APIs)\n└── Extension ClassLoaders (isolated)\n    ├── Extension 1 (e.g., btrace-metrics)\n    ├── Extension 2 (e.g., btrace-statsd)\n    └── Extension N (your extension)\n\nScript ClassLoader (parent = null)\n├── Script classes\n└── Accesses extensions via invokedynamic bridge\n```\n\n### Single Module, Dual Source Sets\n\nUse a single Gradle module with two source sets:\n\n```\nyour-extension/\n├── build.gradle\n└── src/\n    ├── api/java/...        (public API visible to scripts; JDK-only deps)\n    ├── api/resources/...\n    ├── impl/java/...       (implementation; can use external libraries)\n    └── impl/resources/...\n```\n\n- API types are resolved by scripts (end up on bootstrap).\n- Impl is isolated behind an extension classloader with shaded deps.\n- The plugin produces an API JAR, a shadowed Impl JAR, and a distributable ZIP.\n\n## Gradle Setup (Plugin-Based)\n\nApply the BTrace Gradle Extension Plugin and configure your extension via `btraceExtension`:\n\n```gradle\nplugins {\n  id(\"org.openjdk.btrace.extension\") version \"<btraceVersion>\"\n}\n\nrepositories { mavenCentral() }\n\njava {\n  sourceCompatibility = JavaVersion.VERSION_1_8\n  targetCompatibility = JavaVersion.VERSION_1_8\n}\n\ndependencies {\n  // Keep API free of external library types\n  // Put all runtime libs under Impl (the plugin will shade them)\n}\n\nbtraceExtension {\n  id = \"org.example.myext\"                 // required: globally unique extension ID\n  name = \"My Extension\"                    // optional\n  description = \"Does useful things\"       // optional\n\n  // Service interfaces that can be injected into scripts\n  // Auto-detected from @ServiceDescriptor, or declare explicitly:\n  services = [ \"org.example.myext.api.MyService\" ]\n\n  // Shade Impl dependencies to avoid conflicts\n  shadedPackages = [\n    \"com.example.dep\" : \"org.example.myext.shaded.dep\"\n  ]\n\n  // Permissions\n  scanPermissions = true                    // default: infer from Impl bytecode + classpath\n  requiredPermissions = [ ]                 // optional additions/overrides\n\n  // Optional: other extension IDs you depend on\n  requiresExtensions = [ ]\n}\n```\n\nAlternative to the DSL:\n- You can document extension details via the `@ExtensionDescriptor` annotation in your API package’s `package-info.java`.\n- Annotation source: `btrace-core/src/main/java/org/openjdk/btrace/core/extensions/ExtensionDescriptor.java`.\n- Fields: `name`, `version`, `description`, `minBTraceVersion`, `dependencies`, `permissions`.\n- The `btraceExtension` block remains the canonical source for manifest values; `@ExtensionDescriptor` mainly assists tooling and validates that declared `permissions` are covered by scanning or `requiredPermissions`.\n\nOutputs produced by the plugin:\n- API JAR: `build/libs/<name>-<version>-api.jar` (manifest + properties with extension metadata)\n- Impl JAR: `build/libs/<name>-<version>-impl.jar` (shadowed/minimized, isolated at runtime)\n- Distribution ZIP: `build/distributions/<name>-<version>-extension.zip` (bundles API + Impl)\n\nAdvanced (optional) knobs in `btraceExtension`:\n- `autoApplyShadow` (default true): auto-apply Shadow plugin if not applied.\n- `nullableAnnotations`/`nonnullAnnotations`: additional nullability annotations (FQCN) for API linting.\n- `nullabilitySeverity` (`off`|`warn`|`error`): nullability lint severity.\n- `shimabilitySeverity` (`warn`|`error`): shim-compatibility lint severity.\n- `apiCtorSeverity` (`off`|`warn`|`error`): flag public constructors in API classes.\n- `generateShimsReachableOnly` (default true): generate shims only for interfaces reachable from declared services.\n\n## Authoring the API and Impl\n\n### API (src/api/java)\n\nDefine injectable service interfaces. Use the descriptors to help discovery and permission modeling.\n\n```java\npackage org.example.myext.api;\n\nimport org.openjdk.btrace.core.extensions.Permission;\nimport org.openjdk.btrace.core.extensions.ServiceDescriptor;\n\n@ServiceDescriptor(permissions = { Permission.THREADS })\npublic interface MyService {\n  MyMetric metric(String name);\n}\n```\n\nKeep API signatures to JDK and your own API types; avoid external library types.\n\n### Implementation (src/impl/java)\n\nProvide concrete implementations and extend `Extension` to access the runtime context when needed.\n\n```java\npackage org.example.myext.impl;\n\nimport org.openjdk.btrace.core.extensions.Extension;\nimport org.example.myext.api.MyService;\n\npublic final class MyServiceImpl extends Extension implements MyService {\n  public MyServiceImpl() {}\n  // implement API methods...\n}\n```\n\nThe plugin shades external libraries present in Impl according to `shadedPackages`.\n\n## Using Extensions in Scripts\n\n```java\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Injected;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.example.myext.api.MyService;\n\n@BTrace\npublic class MyProbe {\n  @Injected\n  private static MyService svc;\n\n  @OnMethod(clazz = \"com.example.App\", method = \"doWork\")\n  public static void onDoWork() {\n    svc.metric(\"work\");\n  }\n}\n```\n\n## Metadata and Permissions (Auto-Generated)\n\nThe plugin writes extension metadata into the API JAR manifest and a dedicated properties file; manual manifest editing is not needed. Key attributes include:\n- `BTrace-Extension-Id`, `BTrace-Extension-Name`, `BTrace-Extension-Description`\n- `BTrace-Extension-Services` (service interfaces)\n- `BTrace-Extension-Permissions` (merged from scan + explicit `requiredPermissions`)\n- `BTrace-Extension-Requires` (dependent extension IDs)\n- `BTrace-Extension-Impl` (Impl artifact coordinates/path)\n- `BTrace-Shaded-Packages` (diagnostic relocations)\n\nPermission configuration:\n\n```gradle\nbtraceExtension {\n  // Disable inference and declare explicitly (optional)\n  // scanPermissions = false\n  requiredPermissions = [ \"NETWORK\", \"THREADS\" ]\n}\n```\n\nAt runtime, the agent consults this metadata to validate and enforce permissions.\n\n## Dependency Management\n\n- Keep the API free of external library types; prefer JDK and your API classes.\n- Put all runtime libraries in Impl; use `shadedPackages` to relocate and avoid conflicts.\n- Do not include BTrace modules in your Impl artifact; only external libs are shaded.\n\n## Distribution and Installation\n\nBuild artifacts:\n- API JAR: `build/libs/<name>-<version>-api.jar`\n- Impl JAR: `build/libs/<name>-<version>-impl.jar`\n- ZIP: `build/distributions/<name>-<version>-extension.zip`\n\nInstall by copying the ZIP contents (API + Impl) into an extensions directory:\n\n```bash\n# System-wide\nunzip your-extension-<version>-extension.zip -d \"$BTRACE_HOME/extensions/\"\n\n# User-specific\nmkdir -p \"$HOME/.btrace/extensions\"\nunzip your-extension-<version>-extension.zip -d \"$HOME/.btrace/extensions/\"\n```\n\nDiscovery locations:\n1. `$BTRACE_HOME/extensions/*.jar`\n2. `~/.btrace/extensions/*.jar`\n\nConfiguration: `$BTRACE_HOME/conf/extensions.conf`\n\n```hocon\nautoload = true\nrepositories = [ \"${btrace.home}/extensions\", \"${user.home}/.btrace/extensions\" ]\n```\n\n## Testing\n\n- Unit test Impl logic normally (JUnit 5).\n- Integration test with real BTrace scripts in `integration-tests`.\n- Verify on supported JDKs (8, 11, 17+).\n\n## Checklist\n\n- [ ] Single module using `src/api` and `src/impl`\n- [ ] Apply `org.openjdk.btrace.extension` plugin\n- [ ] Set `btraceExtension.id`, declare/annotate `services`\n- [ ] Configure `shadedPackages`; optionally tune `requiredPermissions`\n- [ ] Keep API clean (JDK-only) and small\n- [ ] Build and install ZIP into extensions dir\n- [ ] Unit + integration tests pass on supported JDKs\n\n## Best Practices\n\n### Performance\n- Zero-allocation hot paths; avoid boxing.\n- Prefer lock-free primitives where possible.\n- Lazy init; create objects only when needed.\n- Ensure thread-safety; services can be called concurrently.\n\n### API Design\n- Immutable snapshots for queries.\n- Clear, minimal public surface.\n- Use builders/factories exposed from the service for configuration objects.\n\n### Builder Pattern Example\n\n```java\n// API\n@ServiceDescriptor\npublic interface MetricsService {\n  HistogramConfigBuilder newHistogramConfig();\n  HistogramMetric histogram(String name, HistogramConfig cfg);\n}\n\npublic interface HistogramConfig {}\npublic interface HistogramConfigBuilder {\n  HistogramConfigBuilder lowestDiscernibleValue(long v);\n  HistogramConfigBuilder highestTrackableValue(long v);\n  HistogramConfigBuilder significantDigits(int d);\n  HistogramConfig build();\n}\n\n// Probe (no `new` in scripts)\n@BTrace\nclass HistoProbe {\n  @Injected static MetricsService metrics;\n}\n```\n\n## Troubleshooting\n\n### ClassNotFoundException\n- Script references a type not present in API → move it to `src/api/java` as an interface.\n\n### NoSuchMethodError\n- Impl does not fully implement the API → keep API and Impl in lockstep.\n\n### Extension Not Loaded\n- Missing/incorrect metadata → ensure `btraceExtension.id/services` are set or APIs are annotated.\n\n### Dependency Conflicts\n- Missing relocations → add entries under `shadedPackages` for third-party libraries.\n\n## Summary\n\nUse a single module with `api` and `impl` source sets and the BTrace extension plugin to produce clean, isolated, and self-describing extensions. The plugin handles artifact separation, metadata, permissions, shading, and packaging, so you can focus on a stable API and solid implementation.\n"
  },
  {
    "path": "docs/BTraceTutorial.md",
    "content": "# BTrace Tutorial (BTrace 2.3.0)\n\n## 1. Hello World\n\nAccustoms the learner to 'btrace' command and the way it is used.\nDemonstrates the BTrace ability to instrument a class.\n\n### Setup\n\n#### HelloWorld Class\n\n```java\npackage extra;\n\npublic abstract class HelloWorld extends HelloWorldBase {\n    protected int field = 0;\n\n    public static void main(String[] args) throws Exception {\n        System.out.println(\"ready when you are ...\");\n        System.in.read();\n\n        callA();\n    }\n\n    private static void callA() {\n        HelloWorld instance = new HelloWorldExt();\n        long x = System.nanoTime();\n        instance.callA(\"hello\", 13);\n        System.out.println(\"dur = \" + (System.nanoTime() - x));\n    }\n\n    private void callA(String a, int b) {\n        field++;\n        callB(callC(a, b));\n        field--;\n    }\n\n    private void callB(String s) {\n        field++;\n        System.out.println(\"You want \" + s);\n        field--;\n    }\n\n    protected abstract String callC(String a, int b);\n}\n\nfinal class HelloWorldExt extends HelloWorld {\n    @Override\n    protected String callC(String a, int b) {\n        try {\n            field++;\n            String s = a + \"-\" + b;\n            for (int i = 0; i < 100; i++) {\n                s = callD(s);\n            }\n            return s;\n        } finally {\n            field--;\n        }\n    }\n}\n\nabstract class HelloWorldBase {\n    protected final String callD(String s) {\n        return \"# \" + s;\n    }\n}\n```\n\n### Steps\n\n1. Run the HelloWorld application\n2. Get the HelloWorld application PID via `jps` command\n3. Run `btrace <PID> <HelloWorldTrace.java>`\n4. Proceed with the HelloWorld application\n5. Watch messages being printed\n\nYou will repeat these steps while gradually enhancing the used BTrace script\n\n### Lessons\n\n#### Lesson 1 - Launching BTrace\n\n##### Using `btrace` client to attach to a running JVM\n\n`btrace [opts] <pid> <btrace-script> [<args>]`\n\n* **opts** BTrace specific options; use `btrace -h` to obtain the list of all supported options\n* **pid** process id of the traced Java program\n* **btrace-script** trace program. If it is a \".java\", then it is compiled before submission. Or else, it is assumed to be pre-compiled [i.e., it has to be a .class] and submitted.\n* **args** trace specific arguments\n\nOnce you are attached to the target JVM you can press Ctrl-C in the terminal to show the BTrace console. From there you can either detach and exit or send an event (handled by the __@OnEvent__ annotated methods in the trace program).\n\n##### Starting a Java application with BTrace agent\n\n###### Directly\n\n`java -javaagent:btrace-agent.jar=[<agent-arg>[,<agent-arg>]*]? <launch-args>`\n\nThe agent takes a list of comma separated arguments.\n\n* **noServer** - don't start the socket server\n* **bootClassPath** - boot classpath to be used\n* **systemClassPath** - system classpath to be used\n* **debug** - turns on verbose debug messages (true/false)\n* **trusted** - do not check for btrace restrictions violations (true/false)\n* **dumpClasses** - dump the transformed bytecode to files (true/false)\n* **dumpDir** - specifies the folder where the transformed classes will be dumped to\n* **stdout** - redirect the btrace output to stdout instead of writing it to an arbitrary file (true/false)\n* **probeDescPath** - the path to search for probe descriptor XMLs\n* **startupRetransform** - enable retransform of all the loaded classes at attach (true/false)\n* **scriptdir** - the path to a directory containing scripts to be run at the agent startup\n* **scriptOutputFile** - the path to a file the btrace agent will store its output\n* **grant** - comma-separated list of permissions to grant (e.g. `grant=NETWORK,THREADS`)\n* **deny** - comma-separated list of permissions to deny (e.g. `deny=EXEC,NATIVE`)\n* **grantAll** - grant all permissions (true/false) - use with caution\n* **script** - colon separated list of tracing scripts to be run at the agent startup\n\nThe scripts to be run must have already been compiled to bytecode (a *.class* file) by __btracec__.\n\n###### Using `btracer'\n\n`btracer [opts] <pre-compiled-btrace.class> <vm-arg> <application-args>`\n\n* **opts** BTrace specific options; use `btracer -h` to obtain the list of all supported options\n* **pre-compiled-btrace.class** the trace script compiled to bytecode via __btracec__\n* **vm-args** the VM arguments; eg. `-cp app.jar Main.class` or `-jar app.jar`\n* **application-args** the application specific arguments\n\nYou can use __btracer__ to launch java application from jar (`btracer ... -jar app.jar <application args>`) or a main class (`btracer ... -cp <class_path> <main class> <application args>`)\n\n##### Compiling trace scripts\n\nThis needs to be done in order to launch the Java application with BTrace agent.\n\n`btracec [-cp <classpath>] [-d <directory>] <one-or-more-BTrace-.java-files>`\n\n* **classpath** is the classpath used for compiling BTrace program(s). Default is \".\"\n* **directory** is the output directory where compiled .class files are stored. Default is \".\".\n\nRather than regular *javac* the BTrace compiler is used - causing the script to be validated at compile time and prevent reporting verify errors at runtime.\n\n##### Inspecting the compiled trace scripts\n\nBTrace compiler will, by default, create a binary trace representation which packages the trace class file together with some metadata designed to make the\ntrace loading and application faster. These packages are not directly readable by tools like `javap` and one must use `btracep` instead.\nThe syntax is straightforward - `./btracep <binary trace file>`. The tool will print out\n* trace name\n* verification status (trusted or not)\n* transformation status (will cause class retransformation or not)\n* all probe handlers (all `@OnProbe`, `@OnTimer` etc. definitions)\n* ASM-ified version of the associated \"data holder\" class - the class contains the information that needs to be globally accessible from instrumented code\n\n#### Lesson 2 - Tracing methods\n\nThis is the main purpose of BTrace - inject a custom code to custom locations to give the insights about the internal state and dynamics of the application.\n\n1. Getting just the information that any method is being executed\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"/.*/\")\n    public static void onMethod() {\n        println(\"Hello from method\");\n    }\n}\n```\n\n2. Get the method names\n```java\npackage helloworld;\nimport ...;\n\n@BTrace \npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\")\n    public static void onMethod(@ProbeMethodName String pmn) {\n        println(\"Hello from method \" + pmn);\n    }\n}\n```\n\n3. Intercept only a particular method\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"callA\")\n    public static void onMethod(@ProbeMethodName String pmn) {\n        println(\"Hello from method \" + pmn);\n    }\n}\n```\n\n4. Intercept only a particular method with name matching the handler name\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"#\")\n    public static void callA(@ProbeMethodName String pmn) {\n        println(\"Hello from method \" + pmn);\n    }\n}\n```\n\n5. Intercept methods with names matching certain patterns\n__Note:__ you can use pattern matching for the class names, too\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"/call.*/\")\n    public static void onMethod(@ProbeMethodName String pmn) {\n        println(\"Hello from method \" + pmn);\n    }\n}\n```\n\n6. Intercept methods with names matching certain patterns and inspect their parameters\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"/call.*/\")\n    public static void onMethod(@ProbeMethodName String pmn, AnyType[] args) {\n        println(\"Hello from method \" + pmn);\n        println(\"Received the following parameters:\");\n        printArray(args);\n    }\n}\n```\n\n7. Intercept method with names matching certain patterns and discover their signatures\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"/call.*/\")\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn) {\n        println(\"Hello from method \" + pmn);\n    }\n}\n```\n\n8. Intercept methods for all subclasses and implementations of a certain class/interface\n\n__Note:__ 'extra.HelloWorldBase.callD()' doesn't show up - it is defined in the superclass of 'extra.HelloWorld' and therefore not intercepted.\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"+extra.HelloWorld\", method=\"/call.*/\")\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn) {\n        println(\"Hello from method \" + pmn);\n    }\n}\n```\n\n9. Intercept method with a particular name and signature + capture the method arguments (you need to use the information learned in the previous step)\n\n__Note:__ The order of the un-annotated parameters must correspond to the order of the traced method parameters. Annotated parameters may be placed anywhere.\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorldExt\", method=\"callC\")\n    public static void onMethod(@ProbeMethodName String pmn, String param1, int param2) {\n        println(\"Hello from method \" + pmn);\n        println(\"Arguments: param1 = \" + str(param1) + \", param2 = \" + str(param2));\n    }\n}\n```\n\n10. Intercept method with a particular name and signature but don't capture the method arguments. Here you will need to decifer the VM method signature to get java like method signature. See the @OnMethod.type() javadoc for the java like signature format.\n\nEg. having the VM method signature in form of (Ljava/lang/String;I)V will translate to \"void (java.lang.String, int)\"\n\n__Note:__ We are using overloaded method here and specifying the signature helps BTrace determine which method should be instrumented\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"callA\", type=\"void (java.lang.String, int)\")\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn) {\n        println(\"Hello from method \" + pmn);\n    }\n}\n```\n\n11. Intercept method with a particular name and capture its return value\n`location=@Location(Kind.RETURN)` sets up the instrumentation to be inserted just before the method exits\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"callC\", location=@Location(Kind.RETURN))\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @Return String ret) {\n        println(\"Hello from method \" + pmn + \"; returning \" + ret);\n    }\n}\n```\n\n12. Inspect the content of an instance variable in the method declaring class\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"/call.*/\", location=@Location(Kind.RETURN))\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @Self Object thiz) {\n        println(\"Hello from method \" + pmn);\n        println(\"field = \" + str(getInt(\"field\", thiz)));\n    }\n}\n```\n\nOr retrieve the `java.lang.Field` instance first and perform a check before trying to retrieve the field value.\n\n```java\npackage helloworld;\nimport java.lang.Class;\nimport java.lang.reflect.Field;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"/call.*/\", location=@Location(Kind.RETURN))\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @Self Object thiz) {\n        Class myClz = classOf(thiz);\n        Field fld = field(myClz, \"field\", false);\n        println(\"Hello from method \" + pmn);\n        if (fld != null) {\n           println(\"field = \" + str(getInt(fld, thiz)));\n        }\n    }\n}\n```\n\n13. Get the method execution duration\n\n__Note:__ Need to use @Location(Kind.RETURN) to be able to capture the execution duration\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"/call.*/\", location=@Location(Kind.RETURN))\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @Duration long dur) {\n        println(\"Hello from method \" + pmn);\n        println(\"It took \" + str(dur) + \"ns to execute this method\");\n    }\n}\n```\n\n14. Tracing methods invoked from inside a particular method\n\n__Note:__ 'class', 'method' etc. directly in the @OnMethod annotation will determine where we should look for the invocation of the methods defined by 'class', 'method' etc. parameters in the @Location annotation.\n\n__Note:__ @ProbeMethodName and @ProbeClassName refer to the context method and class; @TargetMethodOrField refers to the traced method invocation\n\n__Note:__ You can use the 'type' annotation parameter in @OnMethod annotation to restrict the context methods and in @Location to restrict the traced method invocations\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"callA\",\n              location=@Location(\n                    value = Kind.CALL,\n                    clazz = \"extra.HelloWorld\",\n                    method = \"/call.*/\",\n                    where = Where.BEFORE)\n    )\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @TargetMethodOrField(fqn = true) String tpmn) {\n        println(\"Hello from method \" + pmn);\n        println(\"Going to invoke method \" + tpmn);\n    }\n}\n```\n\n15. Measuring the duration of methods invoked from inside a particular method\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"callA\",\n              location=@Location(\n                    value = Kind.CALL,\n                    clazz = \"extra.HelloWorld\",\n                    method = \"/call.*/\",\n                    where = Where.AFTER)\n    )\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @TargetMethodOrField(fqn = true) String tpmn, @Duration long dur) {\n        println(\"Hello from method \" + pmn);\n        println(\"Executing \" + tpmn + \" took \" + dur + \"ns\");\n    }\n}\n```\n\n16. Tracing methods invoked from inside a particular method and capturing their parameters\n\n__Note:__ The captured parameters pertain to the invoked method rather than the context method\n\n__Note:__ The @Self annotated parameter captures the context instance and @TargetInstance annotated parameter captures the instance the method is invoked on\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnMethod(clazz=\"extra.HelloWorld\", method=\"callA\",\n              location=@Location(\n                    value = Kind.CALL,\n                    clazz = \"extra.HelloWorld\",\n                    method = \"/call.*/\",\n                    where = Where.BEFORE)\n    )\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @TargetMethodOrField(fqn = true) String tpmn,\n                                @Self Object thiz, @TargetInstance Object tgt, String a, int b) {\n        println(\"Hello from method \" + pmn);\n        println(\"Going to invoke method \" + tpmn);\n        println(\"context = \" + str(classOf(thiz)) + \", target = \" + str(classOf(tgt)));\n        println(\"a = \" + a + \", b = \" + str(b));\n    }\n}\n```\n\n#### Lesson 3 - Global callbacks\n\nGlobal callbacks are not directly related to the tracing code injection but they allow us to observe the global state and act correspondingly.\n\n#### __@OnExit__\n\nCalled when the traced application is about to exit. Allows to capture the exit code.\n\n__Note:__ The signature of the handler method __MUST__ be 'void (int)'\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnExit\n    public static void onexit(int code) {\n        println(\"Application exitting with \" + code);\n    }\n}\n```\n\n#### __@OnError__\n\nCalled whenever an exception is thrown from anywhere in the BTrace handlers.\n\n__Note:__ The signature of the handler method __MUST__ be 'void (java.lang.Throwable)'\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnError\n    public static void onerror(Throwable t) {\n        println(\"Encountered internal error \" + str(t));\n    }\n}\n```\n\n#### __@OnTimer__\n\nAllows to register a handler to be invoked periodically at defined intervals.\n\n__Note:__ The annotation parameter takes the interval value in milliseconds\n\n__Note:__ The signature of the handler method __MUST__ be 'void ()'\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnTimer(1000)\n    public static void ontimer() {\n        println(\"tick ...\");\n    }\n}\n```\n\n#### __@OnEvent__\n\nUsed to raise events from external clients (eg. the command line client). The annotation takes a String parameter which is the event name. When not provided the event is considered to be 'unnamed'.\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnEvent\n    public static void unnamed() {\n        println(\"Received unnamed event\");\n    }\n}\n```\nor\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    @OnEvent(\"myEvent\")\n    public static void myevent() {\n        println(\"Received my event\");\n    }\n}\n```\n\n#### Lesson 4 - Sampling\n\nTracing many methods being executed frequently can bring a significant overhead to the traced application. And often we are not really interested in the high detail data - an aggregated view would do just fine.\n\nTherefore it is possible to employ statistical sampling to reduce the amount of collected data and related overhead while still providing relevant information about the application behaviour.\n\nThe sampling implementation in BTrace guarantees that at least one invocation of a traced method will be recorded, no matter what the sampling settings are.\n\n1. Intercept only each 10th invocation on average\n\n__Note:__ Even though the 'callD' method is executed 100 times we will get only ~10 hits - as dictated by the 'mean' parameter.\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    private static int cntr = 1;\n    @Sampled(kind = Sampled.Sampler.Const, mean = 10)\n    @OnMethod(clazz=\"/extra\\\\.HelloWorld.*/\", method=\"callD\")\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn) {\n        println(\"Hello from method \" + pmn + \" : \" + (cntr++));\n    }\n}\n```\n\n2. Let the sampler mean parameter be adjusted dynamically by keeping to the overhead target\n\n__Note:__ In this case the 'mean' parameter actually specifies the lowest number of nanoseconds the average interval between interceptions should be\n\n__Note:__ Because the adaptive sampling needs to collect timestamps in order to maintain the overhead target the lowest value for the 'mean' parameter is 180 (cca. 60ns for getting start/stop timestamp pair multiplied by the safety margin of 3) \n\n__Note:__ The 'callD' method is very short and the number of iteration is rather limited - we will most probably get only one hit here\n\n```java\npackage helloworld;\nimport ...;\n\n@BTrace\npublic class HelloWorldTrace {\n    private static int cntr = 1;\n    @Sampled(kind = Sampled.Sampler.Adaptive, mean = 50)\n    @OnMethod(clazz=\"/extra\\\\.HelloWorld.*/\", method=\"callD\")\n    public static void onMethod(@ProbeMethodName(fqn = true) String pmn) {\n        println(\"Hello from method \" + pmn + \" : \" + (cntr++));\n    }\n}\n```\n\n#### Lesson 5 - JFR events\n\nSince BTrace 2.1.0 it is possible to define and use JFR dynamic events directly from the BTrace scripts. This gives immediate access to the high-performance\nevent recording engine built directly in JVM. Being able to observe the script defined events in the bigger context of full application/JVM is an additional\nbenefit when comparing to the 'standard' BTrace way of writing the information to stdout or a dedicated text file.\n\n##### Define and use a regular JFR event\n\nA new dynamic event type in BTrace is defined via a `JfrEvent.Factory` instance configured by `@Event` aannotation.\nThe annotation defines the event metadata and event fields.\n\n###### Event Metadata\n\n* **name** - global event name\n* **label** - a pretty printed event name\n* **description** - long description\n* **category** - arbitrary category in 'directory' format (eg. 'Application/SQL/Updates')\n* **stacktrace** - whether the event should collect stacktrace or not\n\n###### Field definition\n\nThe `fields` argument of the `@Event` annotation defines the array of event fields where each field is defined with the help\nof `@Event.Field` annotation.\nThe fields can only be of a supported type (Java primitives + String, Class and Thread) and don't support arrays/lists. \n\n###### Using the event\n\n`BTraceUtils` has been enhanced with the following methods to support working with JFR events:\n* **prepareEvent(eventFactory)** - prepares a new event using the given factory\n* **begin(event)** - calls `begin()` event method to start measuring the event time span\n* **end(event)** - calls `end()` event method to stop measuring the event time span\n* **setEventField(event, field, value)** - sets a field value\n* **commit(event)** - tries and commits the event\n\n###### Example\n```java\n@BTrace public class JfrEventsProbe {\n    @Event(\n        name = \"CustomEvent\",\n        label = \"Custom Event\",\n        fields = {\n            @Event.Field(type = Event.FieldType.INT, name = \"a\"),\n            @Event.Field(type = Event.FieldType.STRING, name = \"b\")\n        }\n    )\n    private static JfrEvent.Factory customEventFactory;\n\n    @OnMethod(clazz = \"/.*/\", method = \"/.*/\")\n    public static void onMethod() {\n        JfrEvent event = prepareEvent(customEventFactory);\n        setEventField(event, \"a\", 10);\n        setEventField(event, \"b\", \"hello\");\n        commit(event);\n    }\n}\n```\n\n##### Define and use a periodic JFR event\n\nA periodic JFR event is automatically generated by JFR at a given time interval or at beginning/end of a JFR chunk.\n\n###### Periodic event handler\n\nA periodic event is defined by an event handler - it is a method by `@PeriodEvent` annotation, pretty much like `@OnMethod` or `@OnTimer` handlers.\nSimilarly to the regular events the annotation defines the event metadata and the event fields.\nIn addition to that the annotation defines the period which can be a time unit like `10 s` or `100 ms` or it can be one of\n`everyChunk`, `beginChunk` or `endChunk`.\n\nThe handler method takes one parameter of `JfrEvent` type. The value of this parameter can be used in the `BTraceUtils` JFR\nspecific methods.\n\n\n###### Example\n```java\n@BTrace public class JfrEventsProbe {\n    @PeriodicEvent(name = \"PeriodicEvent\", fields = @Event.Field(type = Event.FieldType.INT, name = \"ts\", kind = @Event.Field.Kind(name = Event.FieldKind.TIMESTAMP)), period = \"1 s\")\n    public static void onPeriod(JfrEvent event) {\n        if (shouldCommit(event)) {\n            setEventField(event, \"ts\", 1);\n            commit(event);\n        }\n    }\n}\n```\n\n#### Lesson 6 - Extensions and Permissions\n\nBTrace supports extensions that provide additional functionality beyond the core tracing capabilities. Extensions can send metrics to external systems, integrate with DTrace, and more. To ensure safety, extensions require explicit permissions.\n\n##### Permission System\n\nBTrace uses a permission-based security model organized into three tiers:\n\n###### Default Permissions (always granted)\nThese permissions are safe and always available:\n* **MESSAGING** - Send messages to BTrace client\n* **AGGREGATION** - Use aggregation functions\n* **JFR_EVENTS** - Create and use JFR events\n* **PROFILING** - Use profiling functions\n\n###### Standard Permissions (granted unless explicitly denied)\nThese permissions allow read-only access to system information:\n* **FILE_READ** - Read files from disk (limited paths)\n* **SYSTEM_PROPS** - Read system properties\n* **THREAD_INFO** - Read thread information\n* **MEMORY_INFO** - Read memory and GC information\n\n###### Privileged Permissions (require explicit grant)\nThese permissions have security implications and must be explicitly granted:\n* **FILE_WRITE** - Write files to disk\n* **NETWORK** - Network I/O (sockets, HTTP)\n* **THREADS** - Create and manage threads\n* **NATIVE** - Call native code (JNI, Unsafe)\n* **EXEC** - Execute external processes\n* **REFLECTION** - Use reflection\n* **CLASSLOADER** - Access classloaders\n* **UNLIMITED_MEMORY** - Unlimited buffer allocation\n\n##### Permission Model\n\nPermissions are defined by extension/service descriptors and enforced via agent grants. The Gradle plugin writes the effective permission set into the extension’s manifest.\n\n##### Do Not Instantiate Types in Probes\n\n- Probes do not construct arbitrary objects (`new` is not allowed). Instead, obtain builders or factories from injected services and pass built configuration handles back to the service.\n- This keeps hot paths allocation-free and within verifier constraints (only BTraceUtils, injected services, or objects returned from services can be used).\n\nExample:\n```\n@BTrace\nclass Example {\n  @Injected static MetricsService metrics;\n  static final HistogramConfig cfg;\n  static {\n    cfg = metrics.newHistogramConfig().unit(\"ns\").build();\n  }\n  @OnMethod(clazz=\"com.example.Foo\", method=\"bar\", location=@Location(Kind.RETURN))\n  static void onReturn(@Duration long d) {\n    metrics.histogram(\"foo.bar.latency\", cfg).record(d);\n  }\n}\n```\n\n##### Granting Permissions at Runtime\n\nWhen running a probe that requires privileged permissions, you must explicitly grant them:\n\n###### Using the btrace client\n```bash\nbtrace --grant=NETWORK,THREADS <pid> MetricsProbe.class\n```\n\n###### Using the Java agent\n```bash\njava -javaagent:btrace-agent.jar=script=MetricsProbe.class,grant=NETWORK,THREADS ...\n```\n\n###### Grant all permissions (use with caution)\n```bash\nbtrace --grantAll=true <pid> MetricsProbe.class\n```\nor\n```bash\njava -javaagent:btrace-agent.jar=script=MetricsProbe.class,grantAll=true ...\n```\n\n##### Per-Extension Allow/Deny (Simplified Policy)\n- Allow specific extensions to link implementations via agent args:\n  - `-javaagent:btrace-agent.jar=...,allowExtensions=btrace-statsd,my-metrics`\n- Deny specific extensions (implementation blocked; SHIM fallback):\n  - `-javaagent:btrace-agent.jar=...,denyExtensions=legacy-foo`\n- Allow all privileged extensions:\n  - `-javaagent:btrace-agent.jar=...,allowPrivileged=true`\n- Optional process-local policy file:\n  - `-Dbtrace.permissions=/path/to/permissions.properties` or `~/.btrace/permissions.properties`\n  - Example content:\n    - `allowExtensions=btrace-statsd`\n    - `denyExtensions=legacy-foo`\n    - `allowPrivileged=false`\n- Extensions continue to expose required permissions in logs to help operators decide whether to allow them.\n\n##### Permission Error Messages\n\nIf a probe requires permissions that are not granted, BTrace will display a descriptive error message:\n\n```\nProbe requires permissions that are not granted:\n\n  - NETWORK\n    Network I/O (sockets, HTTP). Risk: Data exfiltration, remote connections.\n  - THREADS\n    Create and manage threads. Risk: Resource exhaustion, concurrent operations.\n\nTo allow these permissions, use:\n  --grant=NETWORK,THREADS\n\nOr use --grantAll=true to allow all permissions (not recommended).\n```\n\n##### Inspecting Probe Permissions\n\nUse the `btracep` tool to inspect what permissions a compiled probe requires:\n\n```bash\nbtracep MetricsProbe.class\n```\n\nThe output will include a \"Required permissions\" line listing all permissions the probe needs.\n\n##### Using the StatsdExtension\n\nThe StatsdExtension allows sending metrics to a StatsD server:\n\n```java\n@BTrace\npublic class StatsdExample {\n    @Injected\n    private static StatsdExtension statsd;\n\n    @OnMethod(clazz = \"com.example.API\", method = \"handleRequest\",\n              location = @Location(Kind.RETURN))\n    public static void onRequest(@Duration long duration) {\n        statsd.increment(\"api.requests\");\n        statsd.timing(\"api.latency\", duration / 1_000_000);\n    }\n}\n```\n\nRun with:\n```bash\nbtrace --grant=NETWORK,THREADS -statsd localhost:8125 <pid> StatsdExample.class\n```\n\n##### Using the Histogram Metrics Extension (btrace-metrics)\n\nThe histogram metrics extension provides high-performance in-process metrics using HdrHistogram. It does not require network permissions and runs entirely inside the target JVM.\n\nRequirements:\n- Build the distribution so extensions are exploded under `BTRACE_HOME/extensions/`.\n- The agent discovers built-in extensions automatically; no additional flags are needed.\n\nExample:\n\n```java\npackage myprobes;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.metrics.MetricsService;\nimport org.openjdk.btrace.metrics.histogram.HistogramConfig;\nimport org.openjdk.btrace.metrics.histogram.HistogramMetric;\nimport org.openjdk.btrace.metrics.histogram.HistogramSnapshot;\nimport org.openjdk.btrace.metrics.stats.StatsMetric;\nimport org.openjdk.btrace.metrics.stats.StatsSnapshot;\n\n@BTrace\npublic class HistogramExample {\n    // ServiceType hint is optional; omit for defaults\n    @Injected\n    private static MetricsService metrics;\n\n    private static HistogramMetric histogram;\n    private static StatsMetric stats;\n\n    @OnMethod(clazz = \"com.example.Service\", method = \"doWork\")\n    public static void onEntry() {\n        if (histogram == null) {\n            histogram = metrics.histogramMicros(\"service.doWork\");\n            stats = metrics.stats(\"service.doWork.stats\");\n        }\n    }\n\n    @OnMethod(clazz = \"com.example.Service\", method = \"doWork\", location = @Location(Kind.RETURN))\n    public static void onReturn(@Duration long durationNanos) {\n        long durationMicros = durationNanos / 1000;\n        histogram.record(durationMicros);\n        stats.record(durationMicros);\n    }\n\n    @OnTimer(1000)\n    public static void onTimer() {\n        HistogramSnapshot h = histogram.snapshot();\n        StatsSnapshot s = stats.snapshot();\n\n        println(\"=== Metrics Report ===\");\n        println(\"Count: \" + s.count());\n        println(\"Mean: \" + s.mean() + \" μs\");\n        println(\"Min: \" + s.min() + \" μs\");\n        println(\"Max: \" + s.max() + \" μs\");\n        println(\"P50: \" + h.p50() + \" μs\");\n        println(\"P95: \" + h.p95() + \" μs\");\n        println(\"P99: \" + h.p99() + \" μs\");\n        println(\"======================\");\n    }\n}\n```\n\nRun with:\n```bash\nbtrace <pid> HistogramExample.java\n```\n\nYou should see a periodic metrics report similar to:\n```\n=== Metrics Report ===\nCount: 4\nMean: 4178.5 μs\nMin: 118 μs\nMax: 16341 μs\nP50: 120 μs\nP95: 16343 μs\nP99: 16343 μs\n======================\n```\n\nConfiguration (optional):\n- You can tune defaults in `btrace.conf` (see Architecture: Extension Configuration):\n  - `btrace-metrics.histogram.default-precision=3`\n  - `btrace-metrics.histogram.max-value=3600000000`\n\n##### Troubleshooting Failed Extensions\n\nIf extensions fail to load during agent initialization (for example, due to missing dependencies or configuration issues), BTrace will display a warning when you submit a probe:\n\n```\n[BTRACE WARN] 1 extension(s) failed to load:\n  - StatsdExtension: Missing manifest metadata (ensure Gradle plugin is applied and configured)\nUse 'btrace -le <PID>' for details.\n```\n\n###### Listing Failed Extensions\n\nUse the `-le` option to see detailed information about failed extensions:\n\n```bash\nbtrace -le <pid>\n```\n\nThis will display all extensions that failed to load and the reasons for their failures:\n\n```\nFailed Extensions:\n  1. org.openjdk.btrace.statsd.StatsdExtension: Connection refused to localhost:8125\n  2. org.openjdk.btrace.dtrace.DTraceExtension: DTrace not available on this platform\n```\n\n###### Interactive Menu\n\nWhen attached to a JVM in interactive mode (press Ctrl-C), you can also select option **7** to list failed extensions:\n\n```\nPlease enter your option:\n        1. exit\n        2. send an event\n        3. send a named event\n        4. flush console output\n        5. list probes\n        6. detach client\n        7. list failed extensions\n```\n\nThis is useful for diagnosing issues when probes that rely on specific extensions are not working as expected.\n"
  },
  {
    "path": "docs/ExtensionInterfaceRules.md",
    "content": "# BTrace Extension Interface Rules\n\nThis page defines the rules for authoring BTrace extension APIs (interfaces), the build-time checks enforced by the Gradle plugin, and how optional services use shims or throwing stubs at runtime.\n\n## Overview\n- API vs Impl: Put public service interfaces under `src/api/java`. Implementations live under `src/impl/java` and are shaded/packaged into the implementation JAR.\n- Classloading: The API JAR is added to the target VM bootstrap classpath; the implementation JAR is loaded by an isolated extension classloader.\n- Optional injection: A probe can mark an injected service as optional via `@Injected(optional = true)` and select the fallback mode:\n  - `SHIM` (production): a no‑op object that implements the interface and returns defaults.\n  - `THROW` (development): an object that throws on any method call with a clear error.\n  - Select per-field with `@Injected(mode = SHIM|THROW)`, or globally with `-Dbtrace.extension.shimMode=shim|throw` (default: `throw`).\n\n## Authoring Rules\n- Form:\n  - Public, top‑level interfaces only. No classes or abstract classes.\n  - Java 8 compatible; no default/private methods on interfaces.\n- Signatures:\n  - Only JDK types and other API interfaces in parameter and return types.\n  - No `java.io`, `java.net`, `java.nio.channels`, or `java.lang.reflect` types in signatures.\n  - Do not reference implementation types in API signatures.\n- Exceptions:\n  - No checked exceptions in `throws` clauses.\n- State:\n  - No mutable/static state. Only `public static final` constants are allowed on interfaces.\n- Nullability (required):\n  - Every return and parameter must be annotated with a nullability annotation.\n  - Accepted by default: `javax.annotation.{Nullable, Nonnull}`, `org.jspecify.annotations.{Nullable, NonNull}`, `org.jetbrains.annotations.{Nullable, NotNull}`, `jakarta.annotation.{Nullable, Nonnull}`.\n  - You can configure additional annotations via the plugin (see below).\n- Shimability (optional services):\n  - If a method returns an interface type, annotate it `@Nullable` to ensure the no‑op shim can safely return null.\n  - Primitives return their default Java values in the no‑op shim; `void` methods do nothing.\n- Permissions:\n  - Declare minimal permissions required by the service via `@ServiceDescriptor(permissions = { ... })`, or rely on plugin scanning.\n  - The plugin scans the implementation JAR and classpath by default and writes merged permissions to the API JAR manifest.\n\n## Build‑Time Enforcement\nThe `org.openjdk.btrace.extension` Gradle plugin runs validation on the API services you declare in `btraceExtension.services`. It fails the build with clear error IDs.\n\nEnforced checks (subset shown):\n- `BTRACE-EXT-001`: Service must be a public, top‑level interface.\n- `BTRACE-EXT-002`: Default/private interface methods not allowed (Java 8/shim compatibility).\n- `BTRACE-EXT-003`: Interface declares non‑constant fields.\n- `BTRACE-EXT-010`: Method declares checked exceptions.\n- `BTRACE-EXT-013`: Method uses forbidden signature type (io/net/channels/reflect).\n- `BTRACE-EXT-020`: Missing nullability on method return.\n- `BTRACE-EXT-021`: Missing nullability on a parameter.\n- `BTRACE-EXT-022`: Method returns an interface but is not annotated `@Nullable` (shimability).\n- `BTRACE-EXT-040`: API signature references an implementation class (API purity).\n- `BTRACE-EXT-032`: API annotates required permissions but plugin configuration does not provide them and permission scanning is disabled (enable scanning or declare explicitly).\n\n## Plugin Usage\nApply the plugin in your extension project and declare services:\n\n```\nplugins {\n  id 'org.openjdk.btrace.extension'\n  id 'com.github.johnrengelman.shadow'\n}\n\nbtraceExtension {\n  id = 'btrace-metrics'\n  name = 'BTrace Metrics (HDR)'\n  description = 'HDR Histogram based metrics'\n  services = ['org.openjdk.btrace.metrics.MetricsService']\n  // Optional: configure nullability annotations if you use different ones\n  nullableAnnotations = ['com.acme.NonRequired']\n  nonnullAnnotations = ['com.acme.Required']\n}\n```\n\nBuild tasks wired by the plugin:\n- `validateServiceApis` runs during `check` and fails on violations.\n- `generateServiceShims` and `generateShimIndex` produce shim classes and an index bundled into the API JAR.\n- `packageExtension` produces `*-extension.zip` including API and implementation JARs.\n\nDuring the API JAR build, the plugin logs the permissions written to the manifest:\n\n```\n[BTRACE-EXT] permissions: scanned=[THREADS, REFLECTION] merged=[THREADS, REFLECTION]\n```\n\n## Runtime Fallback (Optional Services)\n- Mark a field in a BTrace script as optional: `@Injected(optional = true)`.\n- Choose mode per field: `@Injected(optional = true, mode = SHIM)` or `THROW`.\n- Or set globally: `-Dbtrace.extension.shimMode=shim|throw` (default: `throw`).\n- The agent prefers pre‑generated shims shipped in the API JAR. If not present, it falls back to a dynamic proxy shim.\n- Required injections (`optional = false`) never fall back and fail fast if unavailable.\n\n## Examples\nCompliant interface:\n\n```\npackage org.openjdk.btrace.metrics;\n\nimport org.openjdk.btrace.core.extensions.Permission;\nimport javax.annotation.Nonnull;\nimport javax.annotation.Nullable;\n\n@ServiceDescriptor(permissions = { Permission.THREADS })\npublic interface MetricsService {\n  void inc(@Nonnull String name);\n\n  @Nullable Meter meter(@Nonnull String name);\n}\n```\n\nViolations (examples):\n- Missing nullability on return/parameter (BTRACE-EXT-020/021)\n- Default method or checked exception on a method (BTRACE-EXT-002/010)\n- Returning an interface without @Nullable (BTRACE-EXT-022)\n- Signature uses `java.io.File` (BTRACE-EXT-013)\n- Signature exposes `impl.InternalMeter` (BTRACE-EXT-040)\n\n---\n\nFor deeper background on extension loading, permission enforcement, and injection, see: `docs/BTraceExtensionDevelopmentGuide.md` and `docs/architecture/ExtensionInvokeDynamicBridge.md`.\n\n## Fixes Appendix\nThis section maps validation errors to concrete fixes you can apply.\n\n- BTRACE-EXT-001: Service must be a public, top-level interface.\n  - Fix: Convert the type to a public top‑level interface (no nested/inner types).\n- BTRACE-EXT-002: Default method not allowed (Java 8/shim compatibility).\n  - Fix: Remove default bodies from interface methods; put behavior in the implementation.\n- BTRACE-EXT-003: Interface declares non‑constant fields.\n  - Fix: Remove fields from interfaces unless they are public static final compile‑time constants.\n- BTRACE-EXT-010: Method declares checked exceptions.\n  - Fix: Remove checked exceptions from API signatures; use unchecked exceptions only if needed.\n- BTRACE-EXT-013: Method uses forbidden type in signature (io/net/channels/reflect).\n  - Fix: Restrict API signatures to JDK types and other API interfaces; avoid I/O, networking, reflection in API surface.\n- BTRACE-EXT-020: Missing nullability on return.\n  - Fix: Annotate the return with @NonNull or @Nullable using your project’s nullability annotations.\n- BTRACE-EXT-021: Missing nullability on a parameter.\n  - Fix: Annotate each parameter with @NonNull or @Nullable.\n- BTRACE-EXT-022: Interface return requires @Nullable (shimability).\n  - Fix: Mark interface return types @Nullable (or provide a documented non‑null default and avoid interface returns when optional).\n- BTRACE-EXT-032: Permissions required by API annotations not covered when scan is disabled.\n  - Fix: Enable `scanPermissions = true` in the plugin or add the missing permissions to `requiredPermissions`.\n- BTRACE-EXT-033: Manifest permissions missing annotated requirements.\n  - Fix: Ensure that the set written to the manifest (from scan + requiredPermissions) includes all permissions declared in `@ServiceDescriptor.permissions` and package-level `@ExtensionDescriptor.permissions`.\n- BTRACE-EXT-040: API signature or constant pool references implementation type.\n  - Fix: Remove any references to classes compiled under `src/impl/java` from API signatures and annotations.\n- BTRACE-EXT-041: Declared service not found in API output.\n  - Fix: Place the interface in `src/api/java` and list it in `btraceExtension.services`.\n- BTRACE-EXT-050: Failed to analyze service (plugin error or unusual bytecode).\n  - Fix: Re‑run with `--stacktrace`. If reproducible, file an issue with the API source and the generated class.\n"
  },
  {
    "path": "docs/FAQ.md",
    "content": "# BTrace Frequently Asked Questions (FAQ)\n\n## General Questions\n\n### What is BTrace?\nBTrace is a safe, dynamic tracing framework for the Java platform. It allows you to dynamically instrument running Java applications to inject tracing code without stopping, recompiling, or modifying the application.\n\n### Is BTrace safe to use in production?\nYes, with proper precautions:\n- **Safe mode** (default): BTrace enforces strict safety checks (no threads, no I/O, no loops)\n- **Sampling**: Use `@Sampled` to reduce overhead\n- **Level control**: Use `@Level` to enable/disable instrumentation dynamically\n- **Test first**: Always test scripts in non-production environments first\n- **Monitor overhead**: Watch for performance impact\n\n**Not recommended in production:**\n- Unsafe mode (`-u` flag)\n- Tracing very high-frequency methods\n- Scripts without sampling on hot paths\n\n### How does BTrace differ from traditional logging?\n| Aspect | BTrace | Traditional Logging |\n|--------|--------|-------------------|\n| Code changes | None required | Requires code modification |\n| Deployment | Dynamic attachment | Requires redeployment |\n| Overhead when disabled | Zero | Some (log statements still evaluated) |\n| Production use | Can add/remove anytime | Fixed at compile time |\n| Flexibility | Change what to log without restart | Fixed logging points |\n| Learning curve | Steeper | Simpler |\n\n### Does BTrace work with all Java applications?\nBTrace works with:\n- Java 8 through Java 20\n- Standard JVMs (HotSpot, OpenJDK)\n- Most application frameworks (Spring, Java EE, etc.)\n- Containerized applications (Docker, Kubernetes)\n\nLimitations:\n- Requires JDK (not JRE) for attach mode\n- Cannot instrument native methods\n- Some restrictions on boot classpath classes\n\n### What's the performance impact of BTrace?\nImpact depends on:\n- **Number of instrumented methods**: More = higher overhead\n- **Method frequency**: Hot paths = significant impact\n- **Handler complexity**: Simple handlers = lower overhead\n- **Sampling rate**: Lower rate = lower overhead\n\nTypical overhead:\n- Well-designed scripts: <5% in production\n- Aggressive instrumentation: 10-50%\n- Poor practices (tracing String.charAt): Can bring system to halt\n\n**Best practices to minimize overhead:**\n```java\n// Use sampling\n@Sampled(kind = Sampled.Sampler.Adaptive)\n\n// Use level control\n@OnMethod(enableAt = @Level(\">=1\"))\n\n// Aggregate instead of printing each event\n@OnTimer(5000)\npublic static void printSummary() { }\n```\n\n## Usage Questions\n\n### Can I use BTrace with Spring Boot applications?\nYes. BTrace works well with Spring Boot:\n\n```java\n// Trace Spring controller methods\n@OnMethod(clazz = \"@org.springframework.web.bind.annotation.RestController\",\n         method = \"@org.springframework.web.bind.annotation.GetMapping\")\n\n// Trace Spring services\n@OnMethod(clazz = \"@org.springframework.stereotype.Service\", method = \"/.*/\")\n\n// Trace specific beans\n@OnMethod(clazz = \"com.example.MyService\", method = \"process\")\n```\n\nFor containerized Spring Boot:\n```bash\ndocker exec -it <container> btrace <PID> script.java\n```\n\n### How do I trace methods from third-party libraries?\nSpecify the fully qualified class name:\n\n```java\n// Trace JDBC\n@OnMethod(clazz = \"java.sql.Statement\", method = \"execute.*\")\n\n// Trace HTTP clients\n@OnMethod(clazz = \"org.apache.http.impl.client.CloseableHttpClient\",\n         method = \"execute\")\n\n// Trace logging frameworks\n@OnMethod(clazz = \"org.slf4j.impl.Log4jLoggerAdapter\", method = \"error\")\n```\n\n### Can I modify method behavior with BTrace?\nNo, BTrace is **read-only**. You can:\n- Observe method calls\n- Read arguments and return values\n- Track timing and frequency\n- Collect statistics\n\nYou cannot:\n- Modify arguments\n- Change return values\n- Skip method execution\n- Modify application state\n\nFor runtime behavior modification, consider:\n- Byteman\n- AspectJ with load-time weaving\n- Java agents with ASM/Byte Buddy\n\n### How do I pass arguments to BTrace scripts?\n```java\n// Script with property\nimport org.openjdk.btrace.core.annotations.*;\n\n@BTrace\npublic class MyTrace {\n    @Property\n    public static String filterValue = \"default\";\n\n    @OnMethod(...)\n    public static void handler(String arg) {\n        if (arg.equals(filterValue)) {\n            println(\"Matched: \" + arg);\n        }\n    }\n}\n```\n\nPass via command line:\n```bash\nbtrace <PID> MyTrace.java filterValue=custom\n```\n\nOr via agent:\n```bash\njava -javaagent:btrace-agent.jar=script=MyTrace.class,filterValue=custom MyApp\n```\n\n### Can I use BTrace with microservices?\nYes, BTrace works well in microservice architectures:\n\n**Per-service tracing:**\n```bash\n# Trace specific service\nkubectl exec -it pod-name -- btrace <PID> script.java\n```\n\n**Common use cases:**\n- Trace REST API endpoints\n- Monitor service-to-service calls\n- Track latency distributions\n- Debug intermittent failures\n\n**Considerations:**\n- Each JVM needs separate BTrace attachment\n- Use service mesh for distributed tracing (Jaeger, Zipkin)\n- BTrace is best for deep debugging, not observability\n\n### How do I trace constructors?\nUse `<init>` for instance constructors, `<clinit>` for static initializers:\n\n```java\n// Instance constructor\n@OnMethod(clazz = \"com.example.MyClass\", method = \"<init>\")\npublic static void onNew() {\n    println(\"Object created\");\n}\n\n// Static initializer\n@OnMethod(clazz = \"com.example.MyClass\", method = \"<clinit>\")\npublic static void onStaticInit() {\n    println(\"Class initialized\");\n}\n```\n\n### Can I save BTrace output to a file?\nYes, redirect output:\n\n```bash\n# Redirect to file\nbtrace <PID> script.java > output.txt\n\n# Or use -o flag\nbtrace -o output.txt <PID> script.java\n```\n\nFor programmatic file writing (requires unsafe mode):\n```bash\nbtrace -u <PID> script.java\n```\n\n```java\nimport java.io.*;\n\n@BTrace(unsafe = true)\npublic class UnsafeFileWriter {\n    private static FileWriter fw;\n\n    @OnMethod(...)\n    public static void handler() throws Exception {\n        if (fw == null) {\n            fw = new FileWriter(\"/tmp/trace.log\");\n        }\n        fw.write(\"Event\\n\");\n        fw.flush();\n    }\n}\n```\n\n## Best Practices\n\n### When should I use BTrace?\n\n**Ideal use cases:**\n- Production debugging (intermittent issues)\n- Performance analysis (method timing, hotspots)\n- Understanding third-party library behavior\n- Troubleshooting without source code access\n- Auditing method calls\n- Learning how frameworks work\n\n**Not ideal for:**\n- Permanent monitoring (use APM tools: New Relic, DataDog)\n- Distributed tracing (use Zipkin, Jaeger)\n- Complex business logic (refactor application)\n- Modifying application behavior (use AOP)\n- Long-term data collection (use metrics libraries)\n\n## Extensions and Injection\n\n### How do I inject extension services?\nUse `@Injected` without parameters for all services/extensions. The invokedynamic injector\ndetects how to construct injected services and extensions. If an extension requires runtime\ncontext, it is initialized via `Extension.initialize(ExtensionContext)`.\n\nSee also: Architecture → `architecture/ExtensionInvokeDynamicBridge.md` and\nExtension Development Guide → `btrace-extension-development-guide.md`.\n\n### What are BTrace anti-patterns?\n\n**1. Tracing everything**\n```java\n// BAD\n@OnMethod(clazz = \"/.*/\", method = \"/.*/\")\npublic static void traceAll() { }\n```\n\n**2. Expensive operations in handlers**\n```java\n// BAD\n@OnMethod(...)\npublic static void handler() {\n    for (int i = 0; i < 1000000; i++) {  // Expensive loop\n        // ...\n    }\n}\n```\n\n**3. No sampling on hot paths**\n```java\n// BAD - called millions of times\n@OnMethod(clazz = \"com.example.HotClass\", method = \"hotMethod\")\npublic static void handler() { }\n\n// GOOD\n@Sampled(kind = Sampled.Sampler.Adaptive)\n@OnMethod(clazz = \"com.example.HotClass\", method = \"hotMethod\")\npublic static void handler() { }\n```\n\n**4. Printing large objects**\n```java\n// BAD - object might be huge\n@OnMethod(...)\npublic static void handler(Object obj) {\n    println(str(obj));  // Could be megabytes\n}\n\n// GOOD\n@OnMethod(...)\npublic static void handler(Object obj) {\n    println(name(classOf(obj)) + \"@\" + str(identityHashCode(obj)));\n}\n```\n\n**5. Forgetting to detach**\n- BTrace keeps instrumentation active even after client disconnects\n- Always properly exit: Ctrl+C → type `exit`\n\n### How do I organize BTrace scripts?\n\n**Directory structure:**\n```\nbtrace-scripts/\n├── common/\n│   ├── MethodTiming.java\n│   └── ExceptionTracker.java\n├── database/\n│   ├── SQLLogger.java\n│   └── ConnectionPoolMonitor.java\n├── http/\n│   ├── RequestLogger.java\n│   └── ResponseTimeTracker.java\n└── memory/\n    └── AllocationTracker.java\n```\n\n**Naming convention:**\n- Descriptive names: `HttpRequestTracker` not `Script1`\n- Purpose-based: `SlowQueryDetector` not `DatabaseTrace`\n- Include target: `SpringControllerTimer`\n\n**Script template:**\n```java\n/*\n * Purpose: [What this script does]\n * Target: [Which application/class]\n * Usage: btrace <PID> ScriptName.java\n * Author: [Your name]\n * Date: [Creation date]\n */\n\nimport org.openjdk.btrace.core.annotations.*;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n@BTrace\npublic class ScriptName {\n    // Script implementation\n}\n```\n\n## Comparison with Other Tools\n\n### BTrace vs. Java Flight Recorder (JFR)\n\n| Feature | BTrace | JFR |\n|---------|--------|-----|\n| Custom instrumentation | Yes | Limited (custom events) |\n| Production overhead | Variable (1-50%) | Very low (<1%) |\n| Learning curve | Moderate | Low |\n| Built into JDK | No | Yes (Java 11+) |\n| Dynamic attachment | Yes | Yes |\n| Historical data | No | Yes (continuous recording) |\n| GUI tools | Limited | Mission Control |\n\n**When to use BTrace over JFR:**\n- Need custom instrumentation points\n- Want to trace specific business logic\n- Need to instrument third-party libraries\n- Want scripting flexibility\n\n**When to use JFR over BTrace:**\n- Need low-overhead continuous monitoring\n- Want comprehensive JVM metrics\n- Prefer GUI-based analysis\n- Need thread dumps and allocation profiling\n\n### BTrace vs. AspectJ\n\n| Feature | BTrace | AspectJ |\n|---------|--------|---------|\n| Runtime attachment | Yes | No (requires weaving) |\n| Code modification | No | Yes |\n| Deployment | Dynamic | Compile-time or load-time |\n| Safety checks | Yes (enforced) | No |\n| Complexity | Low-Medium | High |\n| Use in production | Yes (safe mode) | Yes |\n\n**Use BTrace when:**\n- Need dynamic attachment to running JVM\n- Want to avoid modifying application\n- Need temporary instrumentation\n\n**Use AspectJ when:**\n- Want to modify behavior (not just observe)\n- Need permanent cross-cutting concerns\n- Acceptable to weave at compile/load time\n\n### BTrace vs. Byteman\n\n| Feature | BTrace | Byteman |\n|---------|--------|---------|\n| Primary purpose | Tracing/monitoring | Testing/fault injection |\n| Safety | Enforced (safe mode) | Optional |\n| Script language | Java | Rule-based DSL |\n| Behavior modification | No | Yes |\n| Learning curve | Medium | Medium-High |\n\n**Use BTrace when:**\n- Production monitoring and debugging\n- Want Java-based scripts\n- Need enforced safety\n\n**Use Byteman when:**\n- Testing (fault injection)\n- Simulating failures\n- Need to modify behavior\n\n## Troubleshooting\n\n### Why isn't my script producing output?\nSee [Troubleshooting Guide](troubleshooting.md#no-output-from-scripts) for detailed solutions.\n\nQuick checklist:\n1. Class/method names correct and fully qualified?\n2. Method actually being called?\n3. Imports included?\n4. Using regex correctly (escaped dots)?\n5. Tried verbose mode: `btrace -v`?\n\n### How do I debug a BTrace script?\n```java\n// Add debug output\n@OnMethod(...)\npublic static void handler() {\n    println(\"Handler called!\");\n    println(\"Thread: \" + threadName());\n    println(\"Stack:\");\n    jstack(3);\n}\n\n// Start simple, add complexity\n@OnTimer(1000)\npublic static void heartbeat() {\n    println(\"Script alive at \" + timestamp());\n}\n```\n\n### Can I use BTrace with Java 17+?\nYes, BTrace supports Java 8-20. For Java 9+ you may need to add module opens:\n\n```bash\nbtrace --add-opens java.base/java.lang=ALL-UNNAMED \\\n       --add-opens java.base/jdk.internal.misc=ALL-UNNAMED \\\n       <PID> script.java\n```\n\nOr add to target JVM startup options.\n\n## Advanced Topics\n\n### Can I integrate BTrace with monitoring systems?\nYes, use `@Export` to expose metrics via JMX:\n\n```java\n@BTrace\npublic class MetricsExporter {\n    @Export\n    private static long requestCount;\n\n    @Export\n    private static long errorCount;\n\n    @OnMethod(clazz = \"com.example.Service\", method = \"handleRequest\")\n    public static void onRequest() {\n        requestCount++;\n    }\n\n    @OnMethod(clazz = \"com.example.Service\", method = \"handleRequest\",\n             location = @Location(Kind.ERROR))\n    public static void onError() {\n        errorCount++;\n    }\n}\n```\n\nThen access via JMX or integrate with monitoring tools.\n\n### How does BTrace integrate with JFR?\n\nBTrace has first-class support for Java Flight Recorder (JFR), allowing you to create custom JFR events with <1% overhead.\n\n**Example:**\n```java\nimport org.openjdk.btrace.core.jfr.JfrEvent;\n\n@BTrace\npublic class JfrIntegration {\n    @Event(\n        name = \"MethodExecution\",\n        label = \"Method Execution Event\",\n        category = {\"myapp\", \"performance\"},\n        fields = {\n            @Event.Field(type = Event.FieldType.STRING, name = \"method\"),\n            @Event.Field(type = Event.FieldType.LONG, name = \"duration\")\n        }\n    )\n    private static JfrEvent.Factory execEvent;\n\n    @TLS private static long startTime;\n\n    @OnMethod(clazz = \"com.example.Service\", method = \"process\")\n    public static void onEntry() {\n        startTime = timeNanos();\n    }\n\n    @OnMethod(clazz = \"com.example.Service\", method = \"process\",\n             location = @Location(Kind.RETURN))\n    public static void onReturn(@ProbeMethodName String method) {\n        JfrEvent event = Jfr.prepareEvent(execEvent);\n        if (Jfr.shouldCommit(event)) {\n            Jfr.setEventField(event, \"method\", method);\n            Jfr.setEventField(event, \"duration\", timeNanos() - startTime);\n            Jfr.commit(event);\n        }\n    }\n}\n```\n\nSee [Getting Started: JFR Integration](gettingStarted.md#advanced-jfr-integration) for complete guide.\n\n### When should I use JFR events vs. println output?\n\n**Use JFR events when:**\n- Performance is critical (<1% overhead vs. 1-50% for println)\n- You need timeline visualization in JDK Mission Control\n- You want offline analysis of captured events\n- You're collecting high-frequency data\n- You need correlation with other JVM events\n\n**Use println when:**\n- Quick debugging with immediate console output\n- Low-frequency events\n- Simple ad-hoc tracing\n- No need for structured data\n\n**Performance comparison:**\n```\nJFR events:      <1% overhead\nprintln:         1-50% overhead (depends on frequency)\nAggregations:    ~1-5% overhead\n```\n\n### What's the performance difference between JFR and regular BTrace output?\n\nJFR events are significantly faster because:\n1. **Native recording**: No string formatting or I/O operations\n2. **Binary format**: Events stored in compact binary format\n3. **Async writing**: Events written asynchronously by JVM\n4. **Filtering**: `shouldCommit()` allows JVM-level filtering\n\n**Benchmark results** (1M events):\n- JFR events: ~50ms overhead\n- println to console: ~5000ms overhead\n- println to file: ~500ms overhead\n\n### Can I view BTrace JFR events in JDK Mission Control?\n\nYes! BTrace JFR events appear alongside standard JVM events in Mission Control:\n\n**Steps:**\n1. Run BTrace script with JFR events\n2. Start or dump JFR recording:\n   ```bash\n   jcmd <PID> JFR.start name=my-recording\n   jcmd <PID> JFR.dump name=my-recording filename=recording.jfr\n   ```\n3. Open `recording.jfr` in JDK Mission Control\n4. Navigate to Event Browser → find your custom events\n\nYour BTrace events will have the category you specified (e.g., \"myapp\") and all defined fields.\n\n### What Java versions support BTrace JFR integration?\n\n**Supported:**\n- OpenJDK 8 with backported JFR ✅\n- Java 11+ ✅\n\n**Not supported:**\n- Java 9-10 ❌ (JFR introduced in Java 11, backported to OpenJDK 8)\n\nBTrace gracefully degrades on Java 9-10: JFR event methods return empty events that are silently ignored.\n\n**Version detection:**\n```java\n// BTrace automatically handles version differences\n// No code changes needed for different Java versions\n```\n\n### Does BTrace work with JDK 21 and newer versions?\n\n**Yes**, but with important considerations due to **JEP 451** (introduced in JDK 21):\n\n**Current behavior (JDK 21+):**\n- Dynamic agent loading (BTrace attach mode) still **works** but triggers warnings:\n  ```\n  WARNING: A Java agent has been loaded dynamically\n  ```\n- The warning advises using `-XX:+EnableDynamicAgentLoading` flag\n\n**Solution for JDK 21+:**\n```bash\n# Start your application with this flag to suppress warnings\njava -XX:+EnableDynamicAgentLoading -jar your-application.jar\n```\n\n**Future behavior:**\nIn a future JDK release, dynamic agent loading will be **disabled by default**. The `-XX:+EnableDynamicAgentLoading` flag will be **required** to use BTrace's attach mode.\n\n**Alternatives:**\n1. **Use agent mode** (no attach warnings):\n   ```bash\n   java -javaagent:/path/to/btrace-agent.jar=script=YourScript.class -jar app.jar\n   ```\n2. **Prepare now**: Add `-XX:+EnableDynamicAgentLoading` to your JVM startup scripts for future compatibility\n\nFor details, see [JEP 451: Prepare to Disallow the Dynamic Loading of Agents](https://openjdk.org/jeps/451) and [Troubleshooting: JVM Attachment Issues](troubleshooting.md#jvm-attachment-issues).\n\n### How do I use BTrace in Kubernetes?\n\n**Basic pattern:**\n```bash\n# Find pod and process\nkubectl get pods\nkubectl exec <pod-name> -- jps\n\n# Run BTrace\nkubectl exec -it <pod-name> -- btrace <PID> script.java\n```\n\n**Copy script to pod:**\n```bash\nkubectl cp MyTrace.java <pod-name>:/tmp/\nkubectl exec -it <pod-name> -- btrace <PID> /tmp/MyTrace.java\n```\n\n**Trace multiple pods:**\n```bash\nfor POD in $(kubectl get pods -l app=myapp -o name | cut -d/ -f2); do\n  kubectl exec $POD -- btrace 1 script.java &\ndone\n```\n\n**Prerequisites:**\n- JDK (not JRE) must be in container\n- BTrace must be available in container image\n- Same user permissions as target JVM\n- `shareProcessNamespace: true` for sidecar pattern\n\nSee [Getting Started: Kubernetes](gettingStarted.md#btrace-in-containers-and-kubernetes) and [Troubleshooting: Kubernetes](troubleshooting.md#kubernetes-and-cloud-deployments) for comprehensive guides.\n\n### Can I trace multiple pods simultaneously?\n\nYes, using batch scripts or parallel execution:\n\n**Shell script approach:**\n```bash\n#!/bin/bash\nDEPLOYMENT=$1\nSCRIPT=$2\n\nPODS=$(kubectl get pods -l app=$DEPLOYMENT -o jsonpath='{.items[*].metadata.name}')\n\nfor POD in $PODS; do\n  echo \"Tracing $POD...\"\n  kubectl exec $POD -- btrace 1 $SCRIPT > $POD.log 2>&1 &\ndone\n\nwait\necho \"All traces complete\"\n```\n\n**ConfigMap pattern:**\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: btrace-scripts\ndata:\n  trace.java: |\n    @BTrace\n    public class Trace {\n        // script content\n    }\n```\n\nThen mount and use across all pods. See [Troubleshooting: Batch Tracing](troubleshooting.md#batch-tracing-across-pods).\n\n### What about sidecar vs. init container patterns for BTrace?\n\n**Sidecar Container** (Recommended for persistent tracing):\n```yaml\nspec:\n  shareProcessNamespace: true\n  containers:\n  - name: app\n    image: myapp:latest\n  - name: btrace\n    image: bellsoft/liberica-openjdk-debian:11-cds\n    command: [\"/bin/sh\", \"-c\", \"sleep infinity\"]\n```\n\n**Pros:** Always available, can attach/detach anytime\n**Cons:** Extra resource usage\n**Use when:** Need on-demand tracing capability\n\n**Init Container** (For startup tracing):\n```yaml\nspec:\n  initContainers:\n  - name: setup-btrace\n    image: btrace:latest\n    command: [\"cp\", \"-r\", \"/opt/btrace\", \"/shared\"]\n    volumeMounts:\n    - name: shared\n      mountPath: /shared\n```\n\n**Pros:** No runtime overhead\n**Cons:** Only for startup instrumentation\n**Use when:** Debugging initialization issues\n\n**Agent Mode** (For permanent instrumentation):\n```yaml\nenv:\n- name: JAVA_TOOL_OPTIONS\n  value: \"-javaagent:/opt/btrace-agent.jar=script=/scripts/trace.class\"\n```\n\n**Pros:** Active from process start\n**Cons:** Requires pod restart to change\n**Use when:** Need continuous tracing\n\n### How do I integrate BTrace with Prometheus/Grafana?\n\nBTrace doesn't have direct Prometheus integration, but you can use **StatSD** as a bridge:\n\n**Option 1: StatSD → Prometheus**\n```java\n@BTrace\npublic class MetricsExporter {\n    @OnMethod(clazz = \"com.example.Service\", method = \"handleRequest\")\n    public static void onRequest() {\n        // Send to StatSD (configure with -statsd flag)\n        Statsd.increment(\"requests.total\");\n    }\n\n    @OnMethod(clazz = \"com.example.Service\", method = \"handleRequest\",\n             location = @Location(Kind.ERROR))\n    public static void onError() {\n        Statsd.increment(\"requests.errors\");\n    }\n}\n```\n\nRun with:\n```bash\nbtrace -statsd statsd-exporter:8125 <PID> MetricsExporter.java\n```\n\nThen use [statsd_exporter](https://github.com/prometheus/statsd_exporter) to export to Prometheus.\n\n**Option 2: JMX → Prometheus**\n```java\n@BTrace\npublic class JmxExporter {\n    @Export\n    private static long requestCount;\n\n    @OnMethod(...)\n    public static void handler() {\n        requestCount++;\n    }\n}\n```\n\nUse [jmx_exporter](https://github.com/prometheus/jmx_exporter) to scrape JMX metrics.\n\n**Recommended:** For permanent monitoring, use APM tools (New Relic, DataDog) instead. BTrace is best for ad-hoc debugging.\n\n### Does BTrace work with service meshes (Istio/Linkerd)?\n\nYes, BTrace works with service meshes without interference:\n\n**Why it works:**\n- Service mesh operates at network layer (L7)\n- BTrace operates at JVM bytecode level\n- BTrace uses local sockets (not HTTP)\n- No interaction between mesh sidecars and BTrace\n\n**Considerations:**\n1. **Resource limits**: BTrace overhead may trigger CPU/memory limits\n   ```yaml\n   resources:\n     limits:\n       cpu: \"500m\"      # Increase if needed\n       memory: \"512Mi\"\n   ```\n\n2. **mTLS**: Doesn't affect BTrace (uses local communication)\n\n3. **Port conflicts**: BTrace port 2020 not intercepted by mesh\n\n4. **Multi-container pods**: Use `shareProcessNamespace: true` for sidecar pattern\n\nService mesh telemetry and BTrace serve different purposes:\n- **Service mesh**: Service-to-service observability, distributed tracing\n- **BTrace**: Deep JVM-level debugging, method-level insights\n\nUse both together for comprehensive observability.\n\n### How do I contribute to BTrace?\n1. Sign the [Oracle Contributor Agreement](https://oca.opensource.oracle.com/)\n2. Fork the [repository](https://github.com/btraceio/btrace)\n3. Create a feature branch\n4. Submit a pull request\n\nSee [Contributing Guide](../Readme.md#contributing) for details.\n\n### Where can I find more examples?\n- **Sample scripts**: `btrace-dist/src/main/resources/samples/` (50+ examples)\n- **Tutorial**: [BTrace Tutorial](btraceTutorial.md)\n- **Wiki**: [BTrace Wiki](https://github.com/btraceio/btrace/wiki)\n- **GitHub**: [BTrace Issues](https://github.com/btraceio/btrace/issues) (search for examples)\n\n## Resources\n\n### Documentation\n- **[Documentation Hub](Readme.md)** - Complete documentation map and learning paths\n- [Getting Started Guide](gettingStarted.md)\n- [Quick Reference](quickReference.md)\n- [Troubleshooting Guide](troubleshooting.md)\n- [BTrace Tutorial](btraceTutorial.md)\n- [BTrace Wiki](https://github.com/btraceio/btrace/wiki/Home)\n\n### Community\n- **Slack**: [btrace.slack.com](http://btrace.slack.com/)\n- **Gitter**: [gitter.im/btraceio/btrace](https://gitter.im/btraceio/btrace)\n- **GitHub**: [github.com/btraceio/btrace](https://github.com/btraceio/btrace)\n\n### Related Projects\n- **BTrace Maven Plugin**: [github.com/btraceio/btrace-maven](https://github.com/btraceio/btrace-maven)\n- **VisualVM BTrace Plugin**: [visualvm.github.io](https://visualvm.github.io)\n\n## License\nBTrace is licensed under GPLv2 with the Classpath Exception. See [LICENSE](../LICENSE) for details.\n"
  },
  {
    "path": "docs/GettingStarted.md",
    "content": "# BTrace Getting Started Guide\n\n## What is BTrace?\n\nBTrace is a safe, dynamic tracing tool for the Java platform. It allows you to dynamically instrument running Java applications without stopping them, recompiling code, or adding logging statements. BTrace works by injecting tracing code into the bytecode of target applications at runtime.\n\n**Use BTrace when you need to:**\n- Debug production issues without redeploying\n- Profile application performance in real-time\n- Track method calls, arguments, and return values\n- Monitor memory allocations and object creation\n- Investigate thread behavior and synchronization\n- Capture stack traces at specific points\n\n## Prerequisites\n\n- Java 8 or higher (BTrace supports Java 8-20)\n- Basic knowledge of Java programming\n- Target Java application running with appropriate permissions\n\n## Installation\n\n### Download and Install\n\n1. **Download** the latest release from [GitHub releases](https://github.com/btraceio/btrace/releases/latest)\n\n2. **Extract** the distribution:\n   ```bash\n   # For .tar.gz\n   tar -xzf btrace-<version>.tar.gz\n\n   # For .zip\n   unzip btrace-<version>.zip\n   ```\n\n3. **Set environment variables** (optional but recommended):\n   ```bash\n   export BTRACE_HOME=/path/to/btrace\n   export PATH=$BTRACE_HOME/bin:$PATH\n   ```\n\n### Package Manager Installation\n\n**RPM-based systems (RedHat, CentOS, Fedora):**\n```bash\nsudo rpm -i btrace-<version>.rpm\n```\n\n**Debian-based systems (Ubuntu, Debian):**\n```bash\nsudo dpkg -i btrace-<version>.deb\n```\n\n### JBang Installation (Recommended for Quick Start)\n\n[JBang](https://www.jbang.dev/) makes it incredibly easy to use BTrace without manual installation. It automatically downloads and caches BTrace from Maven Central.\n\n**Install JBang** (one time):\n```bash\n# macOS / Linux\ncurl -Ls https://sh.jbang.dev | bash -s - app setup\n\n# Windows (PowerShell)\niex \"& { $(iwr https://ps.jbang.dev) } app setup\"\n\n# Or use package managers\nbrew install jbangdev/tap/jbang    # macOS\nsdk install jbang                   # SDKMAN\n```\n\n**Use BTrace with JBang** (no separate BTrace installation needed):\n```bash\n# Attach to running application (replace <version> with desired version, e.g., 2.3.0)\njbang io.btrace:btrace-client:<version> <PID> <script.java>\n\n# Add the BTrace JBang catalog (one time), then use the shorter alias\njbang catalog add --name btraceio https://raw.githubusercontent.com/btraceio/jbang-catalog/main/jbang-catalog.json\njbang btrace@btraceio <PID> <script.java>\n```\n\n**Extract agent JARs** (if needed for `--agent-jar`/`--boot-jar` flags):\n```bash\n# Extract to a directory of your choice\njbang io.btrace:btrace-client:<version> --extract-agent ~/.btrace\n\n# This creates:\n#   ~/.btrace/btrace-agent.jar\n#   ~/.btrace/btrace-boot.jar\n\n# Then use them explicitly:\njbang btrace@btraceio --agent-jar ~/.btrace/btrace-agent.jar \\\n             --boot-jar ~/.btrace/btrace-boot.jar \\\n             <PID> <script.java>\n```\n\n**Alternative: Use JARs from Maven local repository:**\nAfter jbang downloads BTrace, find the JARs in your local Maven repository (default `~/.m2`):\n```bash\n# JARs are cached at:\n~/.m2/repository/io/btrace/btrace-agent/<version>/btrace-agent-<version>.jar\n~/.m2/repository/io/btrace/btrace-boot/<version>/btrace-boot-<version>.jar\n\n# Use them directly:\njbang btrace@btraceio --agent-jar ~/.m2/repository/io/btrace/btrace-agent/<version>/btrace-agent-<version>.jar \\\n             --boot-jar ~/.m2/repository/io/btrace/btrace-boot/<version>/btrace-boot-<version>.jar \\\n             <PID> <script.java>\n```\n\n**Benefits:**\n- No manual download or installation\n- Automatic version management via Maven coordinates\n- Works across all platforms (Windows, macOS, Linux)\n- Perfect for CI/CD pipelines and containers\n\n### Verify Installation\n\n```bash\nbtrace -h\n# or with JBang\njbang btrace@btraceio -h\n```\n\nYou should see the BTrace help message with available options.\n\n## 2-Minute Oneliner Quick Start\n\n**New in BTrace:** DTrace-style oneliners let you debug without writing script files!\n\n### Quick Examples\n\n```bash\n# Find your Java application's PID\njps\n\n# Trace method entry with arguments\nbtrace -n 'TestApp::processData @entry { print method, args }' <PID>\n\n# Find slow methods (>50ms)\nbtrace -n 'TestApp::* @return if duration>50ms { print method, duration }' <PID>\n\n# Count method invocations\nbtrace -n 'TestApp::doWork @entry { count }' <PID>\n\n# Print stack traces\nbtrace -n 'TestApp::processData @entry { stack(5) }' <PID>\n```\n\n**Oneliner Syntax:**\n```\nclass-pattern::method-pattern @location [filter] { action }\n```\n\n- **Locations**: `@entry`, `@return`, `@error`\n- **Actions**: `print`, `count`, `time`, `stack`\n- **Filters**: `if duration>NUMBERms`, `if args[N]==VALUE`\n\n**For complete oneliner documentation**, see [Oneliner Guide](onelinerGuide.md).\n\n**Want full BTrace power?** Continue to the full 5-minute quick start below.\n\n## 5-Minute Quick Start\n\nLet's trace a simple Java application to see BTrace in action with full Java scripts.\n\n### Step 1: Prepare a Test Application\n\nCreate a simple Java program (`TestApp.java`):\n\n```java\npublic class TestApp {\n    public static void main(String[] args) throws Exception {\n        System.out.println(\"TestApp started. Press Enter to begin...\");\n        System.in.read();\n\n        while (true) {\n            doWork();\n            Thread.sleep(1000);\n        }\n    }\n\n    private static void doWork() {\n        String result = processData(\"example\", 42);\n        System.out.println(\"Processed: \" + result);\n    }\n\n    private static String processData(String name, int value) {\n        return name + \"-\" + value;\n    }\n}\n```\n\nCompile and run it:\n```bash\njavac TestApp.java\njava TestApp\n```\n\n### Step 2: Create Your First BTrace Script\n\nCreate a BTrace script (`TraceMethods.java`) to trace method calls:\n\n```java\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport static org.openjdk.btrace.core.BTraceUtils.println;\nimport static org.openjdk.btrace.core.BTraceUtils.str;\n\n@BTrace\npublic class TraceMethods {\n    @OnMethod(clazz = \"TestApp\", method = \"processData\")\n    public static void onProcessData(String name, int value) {\n        println(\"Called processData: name=\" + name + \", value=\" + str(value));\n    }\n}\n```\n\n### Step 3: Attach BTrace to the Running Application\n\n1. **Find the process ID** of your TestApp:\n   ```bash\n   jps\n   ```\n   Output will show something like:\n   ```\n   12345 TestApp\n   12346 Jps\n   ```\n\n2. **Attach BTrace**:\n   ```bash\n   btrace 12345 TraceMethods.java\n   ```\n\n3. **Press Enter** in the TestApp window to start processing\n\n4. **Observe the output** in the BTrace terminal:\n   ```\n   Called processData: name=example, value=42\n   Called processData: name=example, value=42\n   ...\n   ```\n\n5. **Detach BTrace**: Press `Ctrl+C` in the BTrace terminal and type `exit`\n\nCongratulations! You've successfully traced your first Java application with BTrace.\n\n## Quick Start: Histogram Metrics Extension\n\nCapture latency distributions and simple stats without external systems using the built-in histogram metrics extension (HdrHistogram-based).\n\n1. Ensure you built the distribution so extensions are available under `BTRACE_HOME/extensions/`.\n2. Create a probe that injects `MetricsService` (no special flags needed):\n\n```java\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.metrics.MetricsService;\nimport org.openjdk.btrace.metrics.histogram.*;\nimport org.openjdk.btrace.metrics.stats.*;\n\n@BTrace\npublic class LatencyProbe {\n   @Injected\n   private static MetricsService metrics;\n   private static HistogramMetric h;\n   private static StatsMetric s;\n\n   @OnMethod(clazz = \"TestApp\", method = \"processData\")\n   public static void onEntry() {\n      if (h == null) {\n         h = metrics.histogramMicros(\"testapp.process\");\n         s = metrics.stats(\"testapp.process.stats\");\n      }\n   }\n\n   @OnMethod(clazz = \"TestApp\", method = \"processData\", location = @Location(Kind.RETURN))\n   public static void onReturn(@Duration long durNs) {\n      long us = durNs / 1000;\n      h.record(us);\n      s.record(us);\n   }\n\n   @OnTimer(1000)\n   public static void report() {\n      HistogramSnapshot hs = h.snapshot();\n      StatsSnapshot ss = s.snapshot();\n      println(\"=== Metrics Report ===\");\n      println(\"Count: \" + ss.count());\n      println(\"Mean: \" + ss.mean() + \" μs\");\n      println(\"Min: \" + ss.min() + \" μs\");\n      println(\"Max: \" + ss.max() + \" μs\");\n      println(\"P50: \" + hs.p50() + \" μs\");\n      println(\"P95: \" + hs.p95() + \" μs\");\n      println(\"P99: \" + hs.p99() + \" μs\");\n      println(\"======================\");\n   }\n}\n```\n\n3. Attach to your running app:\n```bash\nbtrace <PID> LatencyProbe.java\n```\n\nSee the full tutorial section: “Using the Histogram Metrics Extension (btrace-metrics)” in `docs/BTraceTutorial.md` for configuration and details.\n\n## Four Ways to Run BTrace\n\nBTrace offers multiple deployment modes to suit different use cases:\n\n### 1. JBang Mode (Easiest - Recommended)\n\nUse JBang to run BTrace without installation:\n\n```bash\njbang io.btrace:btrace-client:<version> <PID> <script.java>\n\n# One-time catalog setup for the short alias\njbang catalog add --name btraceio https://raw.githubusercontent.com/btraceio/jbang-catalog/main/jbang-catalog.json\n```\n\n**When to use:**\n- Quick start without installation\n- CI/CD pipelines\n- Trying BTrace for the first time\n- Containers and cloud environments\n\n**Examples:**\n```bash\n# Basic usage\njbang btrace@btraceio 12345 MyTrace.java\n\n# With verbose output\njbang btrace@btraceio -v 12345 MyTrace.java arg1 arg2\n\n# Extract agent JARs, then use them explicitly\njbang btrace@btraceio --extract-agent ~/.btrace\njbang btrace@btraceio --agent-jar ~/.btrace/btrace-agent.jar \\\n             --boot-jar ~/.btrace/btrace-boot.jar \\\n             12345 MyTrace.java\n\n# Or use JARs from Maven local repository (after jbang downloads them)\njbang btrace@btraceio --agent-jar ~/.m2/repository/io/btrace/btrace-agent/<version>/btrace-agent-<version>.jar \\\n             --boot-jar ~/.m2/repository/io/btrace/btrace-boot/<version>/btrace-boot-<version>.jar \\\n             12345 MyTrace.java\n```\n\n**Benefits:**\n- Zero installation required\n- Works everywhere (Windows, macOS, Linux, containers)\n- Automatic version management\n- Perfect for reproducible builds\n\n### 2. Attach Mode (Most Common)\n\nAttach to an already running Java process:\n\n```bash\nbtrace [options] <PID> <script.java> [script-args]\n```\n\n**When to use:**\n- Debugging production issues\n- Ad-hoc performance analysis\n- You don't want to restart the application\n\n**Example:**\n```bash\nbtrace -v 12345 MyTrace.java arg1 arg2\n```\n\n**Common options:**\n- `-v` - Verbose output\n- `-p <port>` - Specify port for communication\n- `-o <file>` - Redirect output to file\n- `--agent-jar <path>` - Override agent JAR auto-discovery\n- `--boot-jar <path>` - Override boot JAR auto-discovery\n\n### 3. Java Agent Mode (Pre-compiled Scripts)\n\nStart a Java application with BTrace agent and a pre-compiled script:\n\n```bash\njava -javaagent:btrace-agent.jar=script=<script.class>[,arg1=value1]... YourApp\n```\n\n**When to use:**\n- Tracing from application startup\n- Capturing initialization issues\n- Controlled environments\n\n**Example:**\n```bash\n# First compile the script\nbtracec MyTrace.java\n\n# Then run with agent\njava -javaagent:/path/to/btrace-agent.jar=script=MyTrace.class MyApp\n```\n\n### 4. Launcher Mode (btracer)\n\nUse the `btracer` wrapper to compile and attach in one step:\n\n```bash\nbtracer <script.class> <java-app-with-args>\n```\n\n**When to use:**\n- Local development and testing\n- Quick experiments\n- You have control over application launch\n\n**Example:**\n```bash\n# First compile the script\nbtracec MyTrace.java\n\n# Launch app with trace\nbtracer MyTrace.class java -cp myapp.jar com.example.Main\n```\n\n## Your First BTrace Scripts\n\n### Example 1: Trace Method Entry\n\n```java\nimport org.openjdk.btrace.core.annotations.*;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n@BTrace\npublic class MethodEntry {\n    @OnMethod(clazz = \"com.example.MyClass\", method = \"myMethod\")\n    public static void onEntry() {\n        println(\"Method called!\");\n    }\n}\n```\n\n### Example 2: Trace Method Arguments\n\n```java\nimport org.openjdk.btrace.core.annotations.*;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n@BTrace\npublic class MethodArgs {\n    @OnMethod(clazz = \"com.example.MyClass\", method = \"calculate\")\n    public static void onCalculate(int x, int y) {\n        println(\"calculate called with: x=\" + str(x) + \", y=\" + str(y));\n    }\n}\n```\n\n### Example 3: Trace Method Return Value\n\n```java\nimport org.openjdk.btrace.core.annotations.*;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n@BTrace\npublic class MethodReturn {\n    @OnMethod(clazz = \"com.example.MyClass\", method = \"calculate\", location = @Location(Kind.RETURN))\n    public static void onReturn(@Return int result) {\n        println(\"calculate returned: \" + str(result));\n    }\n}\n```\n\n### Example 4: Measure Method Duration\n\n```java\nimport org.openjdk.btrace.core.annotations.*;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n@BTrace\npublic class MethodDuration {\n    @OnMethod(clazz = \"com.example.MyClass\", method = \"slowMethod\")\n    public static void onEntry(@Duration long durationNanos) {\n        if (durationNanos > 0) {\n            println(\"slowMethod took: \" + str(durationNanos / 1000000) + \" ms\");\n        }\n    }\n}\n```\n\n## Advanced: JFR Integration\n\nBTrace integrates with Java Flight Recorder (JFR) to create high-performance events with <1% overhead. JFR events are recorded natively by the JVM and can be analyzed with JDK Mission Control.\n\n**Requirements:** OpenJDK 8 (with backported JFR) or Java 11+ (not available in Java 9-10)\n\n### Example: Create JFR Event\n\n```java\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n@BTrace\npublic class MyJfrTrace {\n    // Define JFR event factory\n    @Event(\n        name = \"MethodCall\",\n        label = \"Method Call Event\",\n        description = \"Tracks method calls with duration\",\n        category = {\"myapp\", \"performance\"},\n        fields = {\n            @Event.Field(type = Event.FieldType.STRING, name = \"method\"),\n            @Event.Field(type = Event.FieldType.LONG, name = \"duration\")\n        }\n    )\n    private static JfrEvent.Factory callEventFactory;\n\n    @TLS private static long startTime;\n\n    @OnMethod(clazz = \"com.example.MyClass\", method = \"process\")\n    public static void onEntry() {\n        startTime = timeNanos();\n    }\n\n    @OnMethod(clazz = \"com.example.MyClass\", method = \"process\",\n             location = @Location(Kind.RETURN))\n    public static void onReturn(@ProbeMethodName String method) {\n        // Create and commit JFR event\n        JfrEvent event = Jfr.prepareEvent(callEventFactory);\n        if (Jfr.shouldCommit(event)) {\n            Jfr.setEventField(event, \"method\", method);\n            Jfr.setEventField(event, \"duration\", timeNanos() - startTime);\n            Jfr.commit(event);\n        }\n    }\n}\n```\n\n### Viewing JFR Events\n\nAfter running the script, JFR events are recorded in the flight recorder:\n\n```bash\n# Run BTrace script\nbtrace <PID> MyJfrTrace.java\n\n# Start flight recording (if not already running)\njcmd <PID> JFR.start name=my-recording\n\n# Dump recording to file\njcmd <PID> JFR.dump name=my-recording filename=recording.jfr\n\n# Analyze with Mission Control\njmc recording.jfr\n```\n\n**Benefits over println:**\n- <1% overhead vs. 1-50% for println\n- Native JVM recording (no string formatting)\n- Can be analyzed offline\n- Timeline visualization in Mission Control\n\nFor complete JFR documentation, see [BTrace Tutorial Lesson 5](btraceTutorial.md) and [FAQ: JFR Integration](faq.md#jfr-integration).\n\n## BTrace in Containers and Kubernetes\n\nBTrace works in containerized environments with some considerations.\n\n### Docker Containers\n\n**Attach to running container:**\n```bash\n# Find container ID/name\ndocker ps\n\n# Execute BTrace in container\ndocker exec -it <container-id> btrace <PID> script.java\n```\n\n**Prerequisites:**\n- JDK (not JRE) must be installed in container\n- BTrace must be available in container or mounted\n- Same user permissions as target JVM\n\n**Example Dockerfile with official BTrace images:**\n```dockerfile\n# Option 1: Copy BTrace into your application image (recommended)\nFROM btrace/btrace:latest AS btrace\nFROM bellsoft/liberica-openjdk-debian:11-cds\n\nCOPY --from=btrace /opt/btrace /opt/btrace\nENV BTRACE_HOME=/opt/btrace\nENV PATH=$PATH:$BTRACE_HOME/bin\n\n# Your application...\nCOPY target/myapp.jar /app/\nENTRYPOINT [\"java\", \"-jar\", \"/app/myapp.jar\"]\n```\n\n**Alternative: Manual installation (if not using official images):**\n```dockerfile\nFROM bellsoft/liberica-openjdk-debian:11-cds\nRUN curl -L https://github.com/btraceio/btrace/releases/download/v2.2.2/btrace-2.2.2.tar.gz \\\n    | tar -xz -C /opt/\nENV BTRACE_HOME=/opt/btrace-2.2.2\nENV PATH=$PATH:$BTRACE_HOME/bin\n```\n\nSee [docker/Readme.md](../docker/Readme.md) for more Docker usage patterns.\n\n### Kubernetes Pods\n\n**Attach to pod:**\n```bash\n# Find pod and process ID\nkubectl get pods\nkubectl exec <pod-name> -- jps\n\n# Run BTrace\nkubectl exec -it <pod-name> -- btrace <PID> script.java\n```\n\n**Copy script to pod first (if needed):**\n```bash\nkubectl cp MyTrace.java <pod-name>:/tmp/\nkubectl exec -it <pod-name> -- btrace <PID> /tmp/MyTrace.java\n```\n\n**Trace multiple pods:**\n```bash\n# Get all pods for a deployment\nPODS=$(kubectl get pods -l app=myapp -o jsonpath='{.items[*].metadata.name}')\n\n# Attach to each pod\nfor POD in $PODS; do\n  echo \"Tracing $POD...\"\n  kubectl exec $POD -- btrace 1 script.java &\ndone\n```\n\n### Sidecar Pattern\n\nAdd BTrace as a sidecar container for persistent availability:\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: myapp\nspec:\n  template:\n    spec:\n      shareProcessNamespace: true  # Important: enables cross-container process visibility\n      containers:\n      - name: app\n        image: myapp:latest\n\n      - name: btrace\n        image: btrace/btrace:latest-alpine  # Official BTrace Alpine image\n        command: [\"/bin/sh\", \"-c\", \"while true; do sleep 30; done\"]\n        volumeMounts:\n        - name: btrace-scripts\n          mountPath: /scripts\n      volumes:\n      - name: btrace-scripts\n        configMap:\n          name: btrace-scripts\n```\n\n**Note:** Requires `shareProcessNamespace: true` to allow sidecar to see app container processes.\n\n**Using the sidecar:**\n```bash\n# Execute BTrace from sidecar\nkubectl exec <pod-name> -c btrace -- btrace $(pgrep -f myapp) /scripts/trace.btrace\n\n# View output\nkubectl logs <pod-name> -c btrace\n```\n\n### Common Issues in K8s\n\n1. **PID Discovery**: Use `jps` or `ps aux` to find Java process ID\n2. **Port Conflicts**: BTrace uses port 2020 by default; use `-p` flag if needed\n3. **Security Policies**: Pod Security Policies may block ptrace; adjust as needed\n4. **Resource Limits**: BTrace overhead may trigger CPU/memory limits\n\nFor comprehensive troubleshooting, see [Troubleshooting: Kubernetes](troubleshooting.md#kubernetes-and-cloud-deployments).\n\n## Common Pitfalls and Solutions\n\n### 1. Permission Denied / Attachment Fails\n\n**Problem:** `Unable to attach to target VM`\n\n**Solutions:**\n- Ensure BTrace and target app run as the same user\n- **JDK 8-20**: Check if target JVM has `-XX:+DisableAttachMechanism` (remove it)\n- **JDK 21+**: Add `-XX:+EnableDynamicAgentLoading` to target JVM to suppress warnings and ensure compatibility\n- Verify JDK (not JRE) is installed\n\n**Note**: Starting with JDK 21, dynamic agent loading triggers warnings. In a future JDK release, it will be disabled by default, requiring `-XX:+EnableDynamicAgentLoading` to use BTrace's attach mode. See [Troubleshooting: JVM Attachment Issues](troubleshooting.md#jvm-attachment-issues) for details.\n\n### 2. Script Verification Errors\n\n**Problem:** `BTrace script verification failed`\n\n**Common causes:**\n- Using forbidden operations (creating new threads, I/O operations)\n- Calling non-BTrace methods\n- Using synchronization primitives\n\n**Solution:** Use only BTrace-safe operations from `BTraceUtils` class.\n\n### 3. No Output from Script\n\n**Problem:** Script attaches but produces no output\n\n**Checklist:**\n- Verify class and method names are correct (case-sensitive)\n- Check if the method is actually being called in the target app\n- Use regular expressions carefully: `/com\\\\.example\\\\..*/` not `/com.example.*/`\n- Ensure `println()` is imported from `BTraceUtils`\n\n### 4. Script Not Finding Classes\n\n**Problem:** Script doesn't match any classes\n\n**Solutions:**\n- Use fully qualified class names: `\"com.example.MyClass\"` not `\"MyClass\"`\n- For inner classes use `$`: `\"com.example.Outer$Inner\"`\n- Test with wildcards: `\"/com\\\\.example\\\\..*/\"`\n\n### 5. Performance Impact\n\n**Problem:** BTrace slows down the application\n\n**Solutions:**\n- Use sampling: `@Sampled` annotation\n- Add level filtering: `@Level` annotation\n- Limit scope: trace specific methods, not all methods\n- Avoid tracing high-frequency methods\n\n### 6. Unicode or Special Characters in Output\n\n**Problem:** Garbled output with special characters\n\n**Solution:** Set encoding:\n```bash\nbtrace -Dfile.encoding=UTF-8 <PID> script.java\n```\n\n## Next Steps\n\nNow that you have BTrace running, explore these resources:\n\n1. **[BTrace Tutorial](btraceTutorial.md)** - Progressive lessons covering all features\n2. **[Quick Reference](quickReference.md)** - Annotation and API cheat sheet\n3. **[Sample Scripts](../btrace-dist/src/main/resources/samples/)** - 50+ real-world examples\n4. **[Troubleshooting Guide](troubleshooting.md)** - Solutions to common problems\n5. **[BTrace Wiki](https://github.com/btraceio/btrace/wiki/Home)** - Comprehensive user guide\n\n## Tips for Success\n\n- **Start simple**: Begin with basic method tracing before complex instrumentation\n- **Test locally**: Verify scripts on test applications before production use\n- **Use samples**: Browse the 50+ sample scripts for patterns\n- **Monitor overhead**: Always measure BTrace's performance impact\n- **Keep scripts focused**: One script per specific issue\n- **Version control**: Save useful scripts for reuse\n\n## See Also\n\n- **[Documentation Hub](Readme.md)** - Complete documentation map and learning paths\n- **[Quick Reference](quickReference.md)** - Annotation and API cheat sheet\n- **[BTrace Tutorial](btraceTutorial.md)** - Progressive lessons covering all features\n- **[Troubleshooting Guide](troubleshooting.md)** - Solutions to common problems\n- **[FAQ](faq.md)** - Common questions and best practices\n\n## Getting Help\n\n- **Slack**: [btrace.slack.com](http://btrace.slack.com/)\n- **Gitter**: [gitter.im/btraceio/btrace](https://gitter.im/btraceio/btrace)\n- **GitHub Issues**: [github.com/btraceio/btrace/issues](https://github.com/btraceio/btrace/issues)\n- **Wiki**: [github.com/btraceio/btrace/wiki](https://github.com/btraceio/btrace/wiki/Home)\n"
  },
  {
    "path": "docs/OnelinerGuide.md",
    "content": "# BTrace Oneliner Guide\n\nDTrace-style oneliners for quick Java debugging without writing full scripts.\n\n## Overview\n\nBTrace oneliners provide a fast, concise way to debug running Java applications without creating separate script files. Inspired by DTrace oneliners, they compile to standard BTrace Java code internally, ensuring zero performance overhead.\n\n**When to use oneliners:**\n- Quick debugging in production\n- Ad-hoc performance investigation\n- Learning BTrace basics\n- Prototyping before writing full scripts\n\n**When to use full BTrace scripts:**\n- Complex logic with multiple probe points\n- State management across probes\n- Custom data structures\n- Reusable instrumentation\n\n## Quick Start\n\n```bash\n# Basic syntax\nbtrace -n 'class::method @location { action }' <PID>\n\n# Real examples\nbtrace -n 'javax.swing.*::setText @entry { print method, args }' 1234\nbtrace -n 'java.sql.Statement::execute* @return if duration>100ms { print method, duration }' 1234\nbtrace -n 'java.util.HashMap::get @entry { count }' 1234\n```\n\n## Syntax Reference\n\n### Basic Structure\n\n```\nclass-pattern::method-pattern @location [filter] { action [, action]* }\n```\n\n**Components:**\n- `class-pattern` - Class name with wildcards or regex\n- `method-pattern` - Method name with wildcards or regex\n- `@location` - Where to probe: `@entry`, `@return`, or `@error`\n- `filter` (optional) - Conditional filter\n- `action` - What to do: `print`, `count`, `time`, or `stack`\n\n### Class and Method Patterns\n\n**Wildcards** (simple pattern matching):\n```bash\n# Match all classes in package\n'javax.swing.*::*'\n\n# Match all subpackages\n'javax.swing.**::*'\n\n# Match method names\n'MyClass::get*'\n'MyClass::*Service'\n```\n\n**Regex** (advanced pattern matching):\n```bash\n# Regex in class name\n'/com\\.myapp\\..*/::execute'\n\n# Regex in method name\n'java.sql.Statement::/execute.*/'\n\n# Both\n'/com\\.myapp\\..*/::/handle.*/\n```\n\n**Special method names:**\n- `<init>` - Constructors\n- `<clinit>` - Static initializers\n- `*` - All methods\n\n### Locations\n\n| Location | Description | Available Identifiers |\n|----------|-------------|----------------------|\n| `@entry` | Method entry | method, args, self, class |\n| `@return` | Method return | method, args, duration, return, self, class |\n| `@error` | Exception thrown | method, args, duration, self, class |\n\n**Examples:**\n```bash\n# Trace method entry\nbtrace -n 'MyClass::myMethod @entry { print method }' <PID>\n\n# Trace method return\nbtrace -n 'MyClass::myMethod @return { print method, return }' <PID>\n\n# Trace exceptions\nbtrace -n 'MyClass::myMethod @error { print method, stack }' <PID>\n```\n\n### Filters\n\n**Duration filter** (only for `@return` and `@error`):\n```bash\n# Slow methods > 100ms\n'MyClass::* @return if duration>100ms { print method, duration }'\n\n# Very slow methods >= 500ms\n'MyClass::* @return if duration>=500ms { print method }'\n\n# Fast methods < 10ms\n'MyClass::* @return if duration<10ms { print method }'\n```\n\n**Argument filter** (all locations):\n```bash\n# String argument equals\n'MyClass::process @entry if args[0]==\"CREATE\" { print }'\n\n# Numeric argument comparison\n'MyClass::setValue @entry if args[0]>100 { print args }'\n\n# Check null\n'MyClass::process @entry if args[1]==null { print method }'\n```\n\n**Supported comparators:**\n- `>` - Greater than\n- `<` - Less than\n- `==` - Equals\n- `>=` - Greater than or equal\n- `<=` - Less than or equal\n- `!=` - Not equals\n\n### Actions\n\n#### print - Display Values\n\n```bash\n# Print bare message\n{ print }\n\n# Print specific identifiers\n{ print method }\n{ print method, args }\n{ print method, duration, return }\n\n# Available identifiers:\n#   method   - Method name\n#   args     - Method arguments\n#   duration - Execution time (nanoseconds, @return/@error only)\n#   return   - Return value (@return only)\n#   self     - This instance\n#   class    - Class name\n```\n\n**Examples:**\n```bash\n# Method with arguments\nbtrace -n 'MyClass::process @entry { print method, args }' <PID>\n\n# Slow method with timing\nbtrace -n 'MyClass::query @return if duration>100ms { print method, duration }' <PID>\n\n# Return value\nbtrace -n 'MyClass::calculate @return { print method, return }' <PID>\n```\n\n#### count - Count Invocations\n\n```bash\n# Simple count\n{ count }\n```\n\nPrints total count when BTrace exits (Ctrl+C).\n\n**Examples:**\n```bash\n# Count HashMap.get calls\nbtrace -n 'java.util.HashMap::get @entry { count }' <PID>\n\n# Count exceptions\nbtrace -n 'java.lang.Exception::<init> @entry { count }' <PID>\n```\n\n#### time - Show Execution Time\n\n```bash\n# Display execution time in milliseconds\n{ time }\n```\n\nOnly valid for `@return` and `@error` locations.\n\n**Examples:**\n```bash\n# Time database queries\nbtrace -n 'java.sql.Statement::execute* @return { time }' <PID>\n\n# Time method execution\nbtrace -n 'MyClass::expensiveOperation @return { time }' <PID>\n```\n\n#### stack - Print Stack Trace\n\n```bash\n# Full stack trace\n{ stack }\n\n# Limited depth\n{ stack(10) }\n```\n\n**Examples:**\n```bash\n# Stack on OutOfMemoryError\nbtrace -n 'java.lang.OutOfMemoryError::<init> @return { stack(10) }' <PID>\n\n# Call path to method\nbtrace -n 'MyClass::suspiciousMethod @entry { stack(5) }' <PID>\n```\n\n#### Multiple Actions\n\nSeparate actions with commas:\n\n```bash\n# Print and count\n{ print method, count }\n\n# Print, count, and stack\n{ print method, count, stack(3) }\n```\n\n## Common Use Cases\n\n### Performance Debugging\n\n**Find slow database queries:**\n```bash\nbtrace -n 'java.sql.Statement::execute* @return if duration>100ms { print method, duration }' <PID>\n```\n\n**Find slow HTTP requests:**\n```bash\nbtrace -n 'javax.servlet.http.HttpServlet::service @return if duration>500ms { print method, duration }' <PID>\n```\n\n**Time all methods in a class:**\n```bash\nbtrace -n 'com.myapp.MyService::* @return { time }' <PID>\n```\n\n### Monitoring Method Calls\n\n**Trace all Swing UI updates:**\n```bash\nbtrace -n 'javax.swing.*::* @entry { print method, args }' <PID>\n```\n\n**Monitor file operations:**\n```bash\nbtrace -n 'java.io.FileInputStream::<init> @entry { print args }' <PID>\n```\n\n**Count cache hits:**\n```bash\nbtrace -n 'com.myapp.Cache::get @entry { count }' <PID>\n```\n\n### Exception Tracking\n\n**Track all exceptions:**\n```bash\nbtrace -n 'java.lang.Exception::<init> @entry { print self, stack(5) }' <PID>\n```\n\n**Track specific exception:**\n```bash\nbtrace -n 'java.sql.SQLException::<init> @entry { print self, stack(10) }' <PID>\n```\n\n**Monitor OutOfMemoryError:**\n```bash\nbtrace -n 'java.lang.OutOfMemoryError::<init> @return { stack(15) }' <PID>\n```\n\n### Data Flow Tracking\n\n**Track user objects:**\n```bash\nbtrace -n 'com.myapp.User::<init> @entry { print args, count }' <PID>\n```\n\n**Monitor configuration changes:**\n```bash\nbtrace -n 'com.myapp.Config::set* @entry { print method, args }' <PID>\n```\n\n**Track specific argument values:**\n```bash\nbtrace -n 'com.myapp.OrderService::process @entry if args[0]==\"PRIORITY\" { print method, args, stack }' <PID>\n```\n\n### Production Debugging\n\n**Find who's calling deprecated methods:**\n```bash\nbtrace -n 'com.myapp.LegacyService::oldMethod @entry { print stack(3) }' <PID>\n```\n\n**Identify slow REST endpoints:**\n```bash\nbtrace -n 'org.springframework.web.bind.annotation.RequestMapping::* @return if duration>1000ms { print method, duration }' <PID>\n```\n\n**Monitor database connection usage:**\n```bash\nbtrace -n 'javax.sql.DataSource::getConnection @entry { count }' <PID>\n```\n\n## Advanced Examples\n\n### Complex Patterns\n\n**Match multiple packages:**\n```bash\nbtrace -n '/com\\.myapp\\.(service|controller)\\..*/::* @entry { print method }' <PID>\n```\n\n**Match getter/setter methods:**\n```bash\nbtrace -n 'com.myapp.User::/[gs]et.*/ @entry { print method, args }' <PID>\n```\n\n### Combining Features\n\n**Slow methods with stack traces:**\n```bash\nbtrace -n 'com.myapp.*::* @return if duration>200ms { print method, duration, stack(5) }' <PID>\n```\n\n**Count specific argument values:**\n```bash\nbtrace -n 'com.myapp.OrderService::processOrder @entry if args[0]==\"EXPRESS\" { count }' <PID>\n```\n\n**Filter by return value (manual workaround - not directly supported yet):**\n```bash\n# Use duration filter as proxy for successful operations\nbtrace -n 'com.myapp.Service::operation @return if duration>0ms { print return }' <PID>\n```\n\n## Limitations\n\nCurrent limitations of Alternative 1 (Minimal) oneliners:\n\n1. **Single probe point** - Cannot have multiple probes in one oneliner\n2. **No aggregations** - Cannot use histograms, averages, etc.\n3. **No CALL location** - Cannot intercept method calls within methods\n4. **No field access** - Cannot track field reads/writes\n5. **Simple filters only** - No AND/OR logic in filters\n6. **No state** - Cannot maintain variables across invocations\n\n**Future enhancements (Alternative 2):**\n- Multi-probe support: `probe1 | probe2 | probe3`\n- Aggregations: `@hist=histogram; ... { @hist << duration by method }`\n- CALL location: `@call:TargetClass::targetMethod`\n- Grouping: `by method, class`\n\n## Tips and Best Practices\n\n### Performance\n\n1. **Use specific patterns** instead of wildcards when possible:\n   ```bash\n   # Good - specific\n   'com.myapp.UserService::getUserById'\n\n   # Less optimal - very broad\n   '**::*'\n   ```\n\n2. **Add filters** to reduce overhead:\n   ```bash\n   # Only trace slow calls\n   @return if duration>100ms\n   ```\n\n3. **Limit stack depth**:\n   ```bash\n   # Good\n   { stack(5) }\n\n   # Expensive\n   { stack }  # full stack\n   ```\n\n### Debugging Techniques\n\n1. **Start broad, then narrow:**\n   ```bash\n   # Step 1: Find which class\n   btrace -n 'com.myapp.*::* @entry { print class, method }' <PID>\n\n   # Step 2: Focus on specific class\n   btrace -n 'com.myapp.UserService::* @entry { print method, args }' <PID>\n\n   # Step 3: Drill into specific method\n   btrace -n 'com.myapp.UserService::getUserById @entry { print args, stack }' <PID>\n   ```\n\n2. **Use count to quantify issues:**\n   ```bash\n   # How often is this called?\n   btrace -n 'com.myapp.Database::query @entry { count }' <PID>\n   ```\n\n3. **Combine with external tools:**\n   ```bash\n   # Save output to file\n   btrace -n 'com.myapp.*::* @entry { print method }' <PID> > trace.log\n\n   # Pipe to grep\n   btrace -n 'com.myapp.*::* @entry { print method }' <PID> | grep \"User\"\n   ```\n\n### Security\n\n1. **Oneliners run in untrusted mode by default** - Use `-u` flag for trusted operations\n\n2. **Be careful with production** - Test oneliners in staging first\n\n3. **Use read-only actions** - `print`, `count`, `stack` are safe; avoid modifying state\n\n## Troubleshooting\n\n### No Output\n\n**Problem:** Oneliner runs but produces no output\n\n**Solutions:**\n1. Verify the method is being called:\n   ```bash\n   # Add entry point\n   btrace -n 'MyClass::* @entry { print method }' <PID>\n   ```\n\n2. Check pattern matching:\n   ```bash\n   # Try exact match first\n   btrace -n 'com.example.MyClass::myMethod @entry { print }' <PID>\n   ```\n\n3. Verify location:\n   ```bash\n   # Try all locations\n   btrace -n 'MyClass::myMethod @entry { print }' <PID>\n   btrace -n 'MyClass::myMethod @return { print }' <PID>\n   ```\n\n### Syntax Errors\n\n**Problem:** \"Oneliner syntax error at position X\"\n\n**Solutions:**\n1. Check quotes - use single quotes for shell:\n   ```bash\n   # Correct\n   btrace -n 'MyClass::method @entry { print }' <PID>\n\n   # Wrong - shell interprets $\n   btrace -n \"MyClass::method @entry { print }\" <PID>\n   ```\n\n2. Check spacing around symbols:\n   ```bash\n   # Correct\n   if duration>100ms\n\n   # Wrong\n   ifduration>100ms\n   ```\n\n3. Verify filter location:\n   ```bash\n   # Error - duration only for @return/@error\n   '@entry if duration>100ms'\n\n   # Correct\n   '@return if duration>100ms'\n   ```\n\n### Compilation Errors\n\n**Problem:** \"Oneliner compilation failed\"\n\n**Solutions:**\n1. Enable debug mode to see generated code:\n   ```bash\n   btrace -v -n 'MyClass::method @entry { print }' <PID>\n   ```\n\n2. Check for unsupported features:\n   - Duration filter requires `@return` or `@error`\n   - Return identifier requires `@return`\n\n3. Try equivalent full BTrace script to isolate issue\n\n## Converting Oneliners to Full Scripts\n\nWhen you outgrow oneliners, convert them to full BTrace scripts:\n\n**Oneliner:**\n```bash\nbtrace -n 'MyClass::process @return if duration>100ms { print method, duration }' <PID>\n```\n\n**Equivalent BTrace script (MyTrace.java):**\n```java\nimport org.openjdk.btrace.core.annotations.*;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n@BTrace\npublic class MyTrace {\n    @OnMethod(clazz=\"MyClass\", method=\"process\", location=@Location(Kind.RETURN))\n    public static void onProcess(@ProbeMethodName String method, @Duration long duration) {\n        if (duration > 100_000_000L) {  // 100ms in nanoseconds\n            println(method + \" \" + duration);\n        }\n    }\n}\n```\n\n## See Also\n\n- [Getting Started Guide](gettingStarted.md) - Installation and basics\n- [BTrace Tutorial](btraceTutorial.md) - Comprehensive BTrace features\n- [Quick Reference](quickReference.md) - Full annotation reference\n- [FAQ](faq.md) - Common questions\n- [Troubleshooting Guide](troubleshooting.md) - Problem solving\n\n## Feedback\n\nFound an issue or have a suggestion for oneliners? Please:\n- Report on [GitHub Issues](https://github.com/btraceio/btrace/issues)\n- Tag with `oneliner` label\n- Include example oneliner and expected behavior\n"
  },
  {
    "path": "docs/PermissionPolicy.md",
    "content": "# BTrace Permission Policy (Simplified)\n\nMinimal, per-extension policy that decides whether an extension may link its implementation. API\ntypes remain available on the bootstrap classpath so SHIMs can be generated when implementations\nare blocked.\n\n## Sources (first found wins)\n- `-Dbtrace.permissions=/path/to/permissions.properties`\n- `~/.btrace/permissions.properties` or `~/.config/btrace/permissions.properties`\n- Classpath resource `META-INF/btrace/permissions.properties`\n\n## Agent Arguments (optional)\n- `allowExtensions=<id1,id2>`: allow specific extension IDs to link implementations.\n- `denyExtensions=<id1,id2>`: block specific extension IDs (SHIM fallback only).\n- `allowPrivileged=true|false`: allow all privileged extensions to link implementations.\n- Launch-time grants (e.g., `grant=...`, `deny=...`, `grantAll=...`) remain supported but are not\n  part of the policy file and are not required for allow/deny decisions.\n\n## File Format (properties)\n- `allowExtensions=id1,id2`\n- `denyExtensions=id3,id4`\n- `allowPrivileged=false`\n\nExample:\n```\nallowExtensions=btrace-statsd,my-metrics\ndenyExtensions=legacy-foo\nallowPrivileged=false\n```\n\n## Behavior\n- If an extension ID is denied, the implementation is not linked; APIs remain available for SHIMs.\n- If an extension is privileged (declares any privileged required permissions) and is neither\n  explicitly allowed nor covered by `allowPrivileged=true`, its implementation is blocked (SHIMs\n  still available).\n- “Required permissions” remain visible in logs and listings to inform the operator’s decision; no\n  fine-grained per-permission policy evaluation is performed.\n"
  },
  {
    "path": "docs/QuickReference.md",
    "content": "# BTrace Quick Reference\n\nA cheat sheet for experienced users. For step-by-step instructions, see [Getting Started](gettingStarted.md). Back to [README](../Readme.md).\n\n---\n\n## Quick Install\n\n| Method | Command |\n|--------|---------|\n| JBang | `jbang catalog add --name btraceio https://raw.githubusercontent.com/btraceio/jbang-catalog/main/jbang-catalog.json && jbang btrace@btraceio <PID> script.java` |\n| SDKMan | `sdk install btrace` |\n| Docker | `docker pull btrace/btrace` |\n| Manual | [Download latest release](https://github.com/btraceio/btrace/releases/latest) |\n\n---\n\n## Table of Contents\n1. [Core Annotations](#core-annotations)\n2. [Location Kinds](#location-kinds)\n3. [Parameter Annotations](#parameter-annotations)\n4. [Other Annotations](#other-annotations)\n5. [Common Patterns](#common-patterns)\n6. [CLI Commands](#cli-commands)\n7. [Built-in Functions](#built-in-functions)\n\n## Core Annotations\n\n### @BTrace\nMarks a class as a BTrace script.\n```java\n@BTrace\npublic class MyTrace { }\n```\n\n### @OnMethod\nPrimary annotation for method instrumentation.\n\n| Parameter | Type | Description | Example |\n|-----------|------|-------------|---------|\n| `clazz` | String | Target class(es) | `\"com.example.MyClass\"` |\n| `method` | String | Target method(s) | `\"processData\"` |\n| `type` | String | Method signature filter | `\"void (java.lang.String)\"` |\n| `location` | Location | Where to inject code | `@Location(Kind.RETURN)` |\n| `enableAt` | Level | Instrumentation level control | `@Level(\">=1\")` |\n| `exactTypeMatch` | boolean | Exact type matching | `true` |\n\n**Examples:**\n```java\n// Match specific class and method\n@OnMethod(clazz = \"com.example.MyClass\", method = \"myMethod\")\n\n// Match with regex\n@OnMethod(clazz = \"/com\\\\.example\\\\..*/\", method = \"/get.*/\")\n\n// Match by annotation\n@OnMethod(clazz = \"@javax.ws.rs.Path\", method = \"@javax.ws.rs.GET\")\n\n// Match by signature\n@OnMethod(clazz = \"com.example.MyClass\", method = \"calculate\", type = \"int (int, int)\")\n```\n\n### @OnTimer\nExecute periodically.\n```java\n@OnTimer(5000)  // Every 5 seconds\npublic static void periodic() { }\n```\n\n### @OnEvent\nHandle custom events sent from BTrace console.\n```java\n@OnEvent(\"myevent\")\npublic static void onMyEvent() { }\n```\n\n### @OnExit\nExecute when traced process exits.\n```java\n@OnExit\npublic static void onExit(int exitCode) { }\n```\n\n### @OnLowMemory\nExecute when memory is low.\n```java\n@OnLowMemory(pool = \"Tenured Gen\")\npublic static void onLowMemory() { }\n```\n\n### @Event\nDefine a JFR (Java Flight Recorder) event factory for high-performance event recording.\n\n**Requirements:** OpenJDK 8 (with backported JFR) or Java 11+\n\n```java\n@Event(\n    name = \"MyEvent\",\n    label = \"My Custom Event\",\n    description = \"Description of the event\",\n    category = {\"myapp\", \"performance\"},\n    stacktrace = true,\n    fields = {\n        @Event.Field(type = Event.FieldType.STRING, name = \"message\"),\n        @Event.Field(type = Event.FieldType.LONG, name = \"duration\",\n                    kind = @Event.Field.Kind(name = Event.FieldKind.TIMESPAN))\n    }\n)\nprivate static JfrEvent.Factory myEventFactory;\n```\n\n**Field Types:** BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, BOOLEAN, STRING, CLASS, THREAD\n\n**Field Kinds:** TIMESTAMP, TIMESPAN, DATAAMOUNT, FREQUENCY, MEMORYADDRESS, PERCENTAGE, BOOLEANFLAG, UNSIGNED\n\nSee [Getting Started: JFR Integration](gettingStarted.md#advanced-jfr-integration) and Pattern #9 below.\n\n### @PeriodicEvent\nDefine a handler for periodic JFR events (OpenJDK 8 or Java 11+).\n\n```java\n@PeriodicEvent(\n    name = \"PeriodicStats\",\n    label = \"Periodic Statistics\",\n    period = \"10 s\",  // or \"eachChunk\", \"beginChunk\", \"endChunk\"\n    fields = @Event.Field(type = Event.FieldType.LONG, name = \"count\")\n)\npublic static void emitStats(JfrEvent event) {\n    if (Jfr.shouldCommit(event)) {\n        Jfr.setEventField(event, \"count\", getCount());\n        Jfr.commit(event);\n    }\n}\n```\n\n## Location Kinds\n\nSpecify where to inject code within a method using `@Location(Kind.XXX)`.\n\n| Kind | Description | When | Common Parameters |\n|------|-------------|------|-------------------|\n| `ENTRY` | Method entry | Default | Method args |\n| `RETURN` | Method return | Normal exit | `@Return`, `@Duration` |\n| `ERROR` | Exception thrown | Uncaught exception | `Throwable`, `@Duration` |\n| `CALL` | Method call | Before/after call | `@TargetInstance`, `@TargetMethodOrField` |\n| `LINE` | Source line | Specific line | Line number |\n| `FIELD_GET` | Field read | Getting field value | `@TargetInstance`, `@TargetMethodOrField` |\n| `FIELD_SET` | Field write | Setting field value | New value, `@TargetInstance` |\n| `NEW` | Object creation | After `new` | Object type name |\n| `NEWARRAY` | Array creation | After `new[]` | Array type, dimensions |\n| `CATCH` | Exception catch | Entering catch block | `Throwable` |\n| `THROW` | Throwing exception | Before throw | `Throwable` |\n| `ARRAY_GET` | Array read | Getting array element | Array, index |\n| `ARRAY_SET` | Array write | Setting array element | Array, index, value |\n| `SYNC_ENTRY` | Enter synchronized | Acquiring lock | Lock object |\n| `SYNC_EXIT` | Exit synchronized | Releasing lock | Lock object |\n| `INSTANCEOF` | instanceof check | Type check | Type name, `@TargetInstance` |\n| `CHECKCAST` | Type cast | Casting | Type name, `@TargetInstance` |\n\n**Location Modifiers:**\n\n```java\n@Location(value = Kind.CALL, clazz = \"/.*/\", method = \"/.*/\")  // Any call\n@Location(value = Kind.CALL, clazz = \"java.io.File\", method = \"delete\")  // Specific call\n@Location(value = Kind.LINE, line = 42)  // Specific line number\n```\n\n## Parameter Annotations\n\nInject context information into probe handler parameters.\n\n| Annotation | Type | Description | Available In |\n|------------|------|-------------|--------------|\n| `@Self` | Object | Current instance (`this`) | All |\n| `@Return` | Method return type | Return value | `RETURN`, `CALL` (after) |\n| `@Duration` | long | Duration in nanoseconds | `RETURN`, `ERROR`, `CALL` (after) |\n| `@ProbeClassName` | String | Enclosing class name | All |\n| `@ProbeMethodName` | String | Enclosing method name | All |\n| `@TargetInstance` | Object | Target object | `CALL`, `FIELD_GET/SET` |\n| `@TargetMethodOrField` | String | Target name | `CALL`, `FIELD_GET/SET` |\n\n**Examples:**\n```java\n// Method entry with arguments and context\n@OnMethod(clazz = \"MyClass\", method = \"process\")\npublic static void onEntry(@Self Object self,\n                          @ProbeClassName String clazz,\n                          @ProbeMethodName String method,\n                          String arg1, int arg2) { }\n\n// Method return with value and duration\n@OnMethod(clazz = \"MyClass\", method = \"calculate\", location = @Location(Kind.RETURN))\npublic static void onReturn(@Return int result, @Duration long duration) { }\n\n// Method call tracking\n@OnMethod(clazz = \"MyClass\", method = \"/.*/\", location = @Location(Kind.CALL, clazz = \"/.*/\", method = \"/.*/\"))\npublic static void onCall(@TargetInstance Object target, @TargetMethodOrField String method) { }\n```\n\n## Other Annotations\n\n### @Injected\nInjects an extension/service instance into your script.\n\n- Use plain `@Injected` (no parameters). The invokedynamic injector auto-detects\n  whether the service needs a runtime context or a no-arg construction and wires it\n  accordingly.\n- Annotation type: `org.openjdk.btrace.core.annotations.Injected`\n- Example:\n\n```java\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.metrics.MetricsService;\n\n@BTrace\npublic class LatencyProbe {\n  @Injected\n  private static MetricsService metrics;\n}\n```\n\nSee also: Architecture → `architecture/ExtensionInvokeDynamicBridge.md`.\n\n### @Sampled\nControl sampling rate.\n```java\n@Sampled(kind = Sampled.Sampler.Const)  // Constant sampling\n@Sampled(kind = Sampled.Sampler.Adaptive)  // Adaptive sampling\n@OnMethod(...)\npublic static void sampledHandler() { }\n```\n\n### @Level\nControl handler activation by instrumentation level.\n```java\n@OnMethod(clazz = \"...\", enableAt = @Level(\">=1\"))  // Level 1 or higher\n@OnMethod(clazz = \"...\", enableAt = @Level(\"2..5\"))  // Level 2-5 range\n@OnMethod(clazz = \"...\", enableAt = @Level(\"3\"))    // Exactly level 3\n```\n\n### @Export\nExport data via JMX.\n```java\n@Export\nprivate static long counter;\n```\n\n### @Property\nDeclare script properties.\n```java\n@Property\npublic static String configValue = \"default\";\n```\n\n### @TLS (Thread Local Storage)\nPer-thread state.\n```java\n@TLS\nprivate static long threadStartTime;\n```\n\n## Common Patterns\n\n### Pattern 1: Method Entry/Exit Timing\n```java\n@TLS private static long startTime;\n\n@OnMethod(clazz = \"com.example.Service\", method = \"process\")\npublic static void onEntry() {\n    startTime = timeNanos();\n}\n\n@OnMethod(clazz = \"com.example.Service\", method = \"process\", location = @Location(Kind.RETURN))\npublic static void onReturn() {\n    long duration = timeNanos() - startTime;\n    println(\"Duration: \" + str(duration / 1000000) + \" ms\");\n}\n```\n\n### Pattern 2: Method Call Counting\n```java\nprivate static Map<String, AtomicInteger> counts = Collections.newHashMap();\n\n@OnMethod(clazz = \"com.example.Service\", method = \"/.*/\")\npublic static void onMethod(@ProbeMethodName String method) {\n    AtomicInteger counter = Collections.get(counts, method);\n    if (counter == null) {\n        counter = Atomic.newAtomicInteger(0);\n        Collections.put(counts, method, counter);\n    }\n    Atomic.incrementAndGet(counter);\n}\n\n@OnTimer(5000)\npublic static void printStats() {\n    printMap(counts);\n}\n```\n\n### Pattern 3: Exception Tracking\n```java\n@OnMethod(clazz = \"com.example.Service\", method = \"/.*/\", location = @Location(Kind.ERROR))\npublic static void onError(@ProbeClassName String clazz,\n                          @ProbeMethodName String method,\n                          Throwable t) {\n    println(\"Exception in \" + clazz + \".\" + method + \": \" + str(t));\n    jstack();\n}\n```\n\n### Pattern 4: Field Access Monitoring\n```java\n@OnMethod(clazz = \"com.example.State\", method = \"/.*/\", location = @Location(Kind.FIELD_SET, clazz = \"/.*/\", field = \"status\"))\npublic static void onFieldSet(@TargetInstance Object target,\n                             @TargetMethodOrField String field,\n                             Object newValue) {\n    println(\"Field \" + field + \" set to: \" + str(newValue));\n}\n```\n\n### Pattern 5: SQL Query Logging\n```java\n@OnMethod(clazz = \"java.sql.Statement\", method = \"execute.*\")\npublic static void onSqlExecute(@Self Object stmt, String sql) {\n    println(\"SQL: \" + sql);\n}\n```\n\n### Pattern 6: HTTP Request Tracking\n```java\n@OnMethod(clazz = \"+javax.servlet.http.HttpServlet\", method = \"service\")\npublic static void onRequest(@Self Object servlet,\n                            javax.servlet.http.HttpServletRequest req) {\n    println(str(req.getMethod()) + \" \" + str(req.getRequestURI()));\n}\n```\n\n### Pattern 7: Object Allocation Tracking\n```java\nprivate static long objectCount;\n\n@OnMethod(clazz = \"com.example.HeavyObject\", method = \"<init>\")\npublic static void onNew() {\n    objectCount++;\n}\n\n@OnTimer(5000)\npublic static void printCount() {\n    println(\"Objects created: \" + str(objectCount));\n}\n```\n\n### Pattern 8: Aggregations\n```java\nprivate static Aggregation distrib = Aggregations.newAggregation(AggregationFunction.QUANTIZE);\n\n@OnMethod(clazz = \"com.example.Service\", method = \"process\", location = @Location(Kind.RETURN))\npublic static void onReturn(@Duration long duration) {\n    Aggregations.addToAggregation(distrib, duration / 1000000);  // Convert to ms\n}\n\n@OnTimer(10000)\npublic static void printDistribution() {\n    Aggregations.printAggregation(\"Duration distribution (ms)\", distrib);\n}\n```\n\n### Pattern 9: JFR Event Recording\n```java\nimport org.openjdk.btrace.core.jfr.JfrEvent;\n\n@BTrace\npublic class JfrMethodTrace {\n    @Event(\n        name = \"MethodExecution\",\n        label = \"Method Execution Event\",\n        category = {\"myapp\"},\n        fields = {\n            @Event.Field(type = Event.FieldType.STRING, name = \"className\"),\n            @Event.Field(type = Event.FieldType.STRING, name = \"methodName\"),\n            @Event.Field(type = Event.FieldType.LONG, name = \"duration\",\n                        kind = @Event.Field.Kind(name = Event.FieldKind.TIMESPAN))\n        }\n    )\n    private static JfrEvent.Factory execEventFactory;\n\n    @TLS private static long startTime;\n\n    @OnMethod(clazz = \"com.example.Service\", method = \"/.*/\")\n    public static void onEntry() {\n        startTime = timeNanos();\n    }\n\n    @OnMethod(clazz = \"com.example.Service\", method = \"/.*/\",\n             location = @Location(Kind.RETURN))\n    public static void onReturn(@ProbeClassName String clazz,\n                               @ProbeMethodName String method) {\n        JfrEvent event = Jfr.prepareEvent(execEventFactory);\n        if (Jfr.shouldCommit(event)) {\n            Jfr.setEventField(event, \"className\", clazz);\n            Jfr.setEventField(event, \"methodName\", method);\n            Jfr.setEventField(event, \"duration\", timeNanos() - startTime);\n            Jfr.commit(event);\n        }\n    }\n}\n```\n\n**Benefits:** <1% overhead, native JVM recording, offline analysis with Mission Control.\n\n## CLI Commands\n\n### btrace\nAttach to running JVM and trace.\n```bash\nbtrace [options] <PID> <script.java> [script-args]\n```\n\n**Common Options:**\n- `--version` - Show the version\n- `-v` - Run in verbose mode\n- `-l` - List all locally attachable JVMs\n- `-lp` - List active probes in the given JVM (expects PID or app name)\n- `-r <probe-id>` - Reconnect to an active disconnected probe\n- `-r help` - Show help on remote commands\n- `-o <file>` - Output to file (disables console output)\n- `-u` - Run in trusted/unsafe mode\n- `-d <path>` - Dump instrumented classes to specified path\n- `-pd <path>` - Search path for probe XML descriptors\n- `-cp <path>` / `-classpath <path>` - User class files and annotation processors path\n- `-I <path>` - Include files path\n- `-p <port>` - Port for btrace agent listener (default: 2020)\n- `-host <host>` - Remote host (default: localhost)\n- `-statsd <host:port>` - StatSD server configuration\n- `-x` - Unattended mode (non-interactive)\n\n**Examples:**\n```bash\n# List all Java processes\nbtrace -l\n\n# Basic attach\nbtrace 12345 MyTrace.java\n\n# Verbose with output file\nbtrace -v -o trace.log 12345 MyTrace.java\n\n# List active probes in a JVM\nbtrace -lp 12345\n\n# Reconnect to an active probe\nbtrace -r myprobe-id 12345\n\n# With script arguments\nbtrace 12345 MyTrace.java arg1 arg2\n\n# Dump instrumented classes for debugging\nbtrace -d /tmp/instrumented 12345 MyTrace.java\n\n# With StatSD integration\nbtrace -statsd localhost:8125 12345 MyTrace.java\n```\n\n### btracec\nCompile BTrace script.\n```bash\nbtracec <script.java>\n```\n\n**Examples:**\n```bash\n# Compile script\nbtracec MyTrace.java\n\n# Results in MyTrace.class\n```\n\n### btracer\nLaunch Java app with BTrace agent.\n```bash\nbtracer <script.class> <java-app-and-args>\n```\n\n**Examples:**\n```bash\n# First compile\nbtracec MyTrace.java\n\n# Then launch\nbtracer MyTrace.class java -jar myapp.jar\n\n# With JVM options\nbtracer MyTrace.class java -Xmx2g -jar myapp.jar\n```\n\n### Java Agent Mode\nStart app with BTrace agent directly.\n```bash\njava -javaagent:/path/to/btrace-agent.jar=script=<script.class>[,arg=value]... YourApp\n```\n\n**Agent Parameters:**\n- `script=<path>` - BTrace script class file\n- `scriptdir=<dir>` - Directory to load scripts from\n- `port=<port>` - Communication port\n- `noServer=true` - Don't start command server\n- `bootClassPath=<path>` - Additional boot classpath\n\n**Examples:**\n```bash\n# Basic agent mode\njava -javaagent:btrace-agent.jar=script=MyTrace.class MyApp\n\n# With custom port\njava -javaagent:btrace-agent.jar=script=MyTrace.class,port=2020 MyApp\n```\n\n## Built-in Functions\n\nAll functions from `org.openjdk.btrace.core.BTraceUtils`.\n\n### Output Functions\n```java\nprintln(String)           // Print line\nprint(String)            // Print without newline\nprintArray(Object[])     // Print array\nprintMap(Map)            // Print map\nprintf(String, ...)      // Formatted print\n```\n\n### Reflection Functions\n```java\nstr(Object)              // Object to string\nname(Class)              // Class name\nprobeClass()             // Get current probe class\nclassOf(Object)          // Get object's class\nfield(Class, String)     // Get field value\n```\n\n### Aggregation Functions\n```java\nnewAggregation(AggregationFunction)    // Create aggregation\naddToAggregation(Aggregation, long)     // Add value\nprintAggregation(String, Aggregation)   // Print distribution\n```\n\n### Time Functions\n```java\ntimeMillis()             // Current time in milliseconds\ntimeNanos()              // Current time in nanoseconds\ntimestamp()              // Formatted timestamp\n```\n\n### Thread Functions\n```java\njstack()                 // Print stack trace\njstack(int)              // Print N frames\njstacks()                // Print all thread stacks\nthreadId()               // Current thread ID\nthreadName()             // Current thread name\n```\n\n### Collection Functions\n```java\nCollections.newHashMap()      // Create HashMap\nCollections.newArrayList()    // Create ArrayList\nCollections.put(Map, K, V)    // Put in map\nCollections.get(Map, K)       // Get from map\nCollections.size(Collection)  // Get size\n```\n\n### Atomic Functions\n```java\nAtomic.newAtomicInteger(int)        // Create AtomicInteger\nAtomic.incrementAndGet(AtomicInteger)  // Increment and get\nAtomic.get(AtomicInteger)            // Get value\n```\n\n### System Functions\n```java\nexit(int)                // Exit BTrace\nsys(String)              // System property\ngetenv(String)           // Environment variable\ngetInstrumentationLevel()  // Current level\n```\n\n### Memory Functions\n```java\nsizeof(Object)           // Object size\nheapUsage()              // Heap memory usage\nnonHeapUsage()           // Non-heap memory usage\n```\n\n### JFR Event Operations\n```java\n// Create event from factory\nJfr.prepareEvent(JfrEvent.Factory)    // Create new JFR event instance\n\n// Set event field values (overloaded for all types)\nJfr.setEventField(JfrEvent, String, byte|boolean|char|short|int|float|long|double|String)\n\n// Event lifecycle\nJfr.shouldCommit(JfrEvent)             // Check if event should be recorded\nJfr.commit(JfrEvent)                   // Commit event to JFR\nJfr.begin(JfrEvent)                    // Start timing for timespan events\nJfr.end(JfrEvent)                      // End timing for timespan events\n```\n\n**Note:** JFR functions require OpenJDK 8 (with backported JFR) or Java 11+. Not available in Java 9-10 (graceful degradation).\n\n## Restrictions\n\nBTrace scripts have safety restrictions:\n- No new threads\n- No new classes\n- No synchronization\n- No loops (for, while, do-while, enhanced for)\n- No external method calls (methods within same BTrace class are allowed)\n- No file I/O (except via BTraceUtils)\n- No System.exit\n\nUse `-u` (unsafe mode) to bypass restrictions, but only in controlled environments.\n\n---\n\n## See Also\n\n- **[Documentation Hub](Readme.md)** - Complete documentation map and learning paths\n- **[Getting Started Guide](gettingStarted.md)** - Installation, first script, and quick start\n- **[BTrace Tutorial](btraceTutorial.md)** - Progressive lessons covering all features\n- **[Troubleshooting Guide](troubleshooting.md)** - Solutions to common problems\n- **[FAQ](faq.md)** - Common questions and best practices\n"
  },
  {
    "path": "docs/README.md",
    "content": "# BTrace Documentation\n\nWelcome to the BTrace documentation! BTrace is a safe, dynamic tracing tool for the Java platform that allows you to instrument running applications without stopping them.\n\n## Quick Start\n\n**New to BTrace?** Start here → [Getting Started Guide](gettingStarted.md)\n\nGet up and running in 5 minutes with installation, your first script, and common usage patterns.\n\n## Documentation Map\n\n| Document | Description | Target Audience |\n|----------|-------------|-----------------|\n| **[Getting Started](gettingStarted.md)** | Installation, first script, deployment modes, common pitfalls | New users, quick start |\n| **[Oneliner Guide](onelinerGuide.md)** | DTrace-style oneliners for quick debugging without scripts | Quick debugging, ops/SRE |\n| **[Quick Reference](quickReference.md)** | Annotations, patterns, CLI commands, built-in functions | Experienced users, quick lookup |\n| **[BTrace Tutorial](btraceTutorial.md)** | Comprehensive lessons covering all features | All users, in-depth learning |\n| **[Troubleshooting Guide](troubleshooting.md)** | Common errors, debugging, performance, compatibility | Problem-solving, debugging |\n| **[FAQ](faq.md)** | Common questions, best practices, comparisons | All users, decision-making |\n\n## Learning Paths\n\n### I'm New to BTrace\n1. Read [Getting Started Guide](gettingStarted.md) (10 minutes)\n2. Try the 5-minute quick start example\n3. Learn [Oneliner syntax](onelinerGuide.md) for quick debugging (5 minutes)\n4. Explore [BTrace Tutorial](btraceTutorial.md) lessons 1-3\n5. Keep [Quick Reference](quickReference.md) handy\n\nTip: Want latency histograms fast? See [Quick Start: Histogram Metrics Extension](gettingStarted.md#quick-start-histogram-metrics-extension) and the tutorial section [Using the Histogram Metrics Extension](btraceTutorial.md#using-the-histogram-metrics-extension-btrace-metrics).\n\n### I Need to Solve a Problem\n1. Check [Troubleshooting Guide](troubleshooting.md) for your error\n2. Search [FAQ](faq.md) for similar issues\n3. Review [Getting Started](gettingStarted.md) common pitfalls\n4. Ask on [Slack](http://btrace.slack.com/) or [Gitter](https://gitter.im/btraceio/btrace)\n\n### I Need a Quick Lookup\n- **Quick Debug?** → [Oneliner Guide](onelinerGuide.md) for DTrace-style one-line commands\n- **Annotations?** → [Quick Reference: Core Annotations](quickReference.md#core-annotations)\n- **CLI Commands?** → [Quick Reference: CLI Commands](quickReference.md#cli-commands)\n- **Common Patterns?** → [Quick Reference: Common Patterns](quickReference.md#common-patterns)\n- **Built-in Functions?** → [Quick Reference: Built-in Functions](quickReference.md#built-in-functions)\n\n### I Want Advanced Features\n1. **JFR Integration** → [Getting Started: JFR Integration](gettingStarted.md#advanced-jfr-integration), [Tutorial Lesson 5](btraceTutorial.md)\n2. **Sampling** → [Quick Reference: @Sampled](quickReference.md#sampled), [FAQ: Performance](faq.md#performance-issues)\n3. **Aggregations** → [Quick Reference: Aggregation Functions](quickReference.md#aggregation-functions)\n4. **Cloud Deployments** → [Getting Started: K8s](gettingStarted.md#btrace-in-containers-and-kubernetes), [FAQ: K8s](faq.md#can-i-use-btrace-with-microservices)\n5. **Level Filtering** → [Quick Reference: @Level](quickReference.md#level)\n6. **Extensions Architecture** → [Extension invokedynamic Bridge](architecture/ExtensionInvokeDynamicBridge.md)\n\n## Documentation by Topic\n\n### Core Features\n- **Method Tracing** → [Tutorial Lesson 1](btraceTutorial.md), [Quick Reference: @OnMethod](quickReference.md#onmethod)\n- **Timing & Duration** → [Quick Reference: @Duration](quickReference.md#parameter-annotations), [Pattern: Method Timing](quickReference.md#pattern-1-method-entrye xit-timing)\n- **Exception Tracking** → [Quick Reference: Kind.ERROR](quickReference.md#location-kinds), [Pattern: Exception Tracking](quickReference.md#pattern-3-exception-tracking)\n- **Field Access** → [Quick Reference: Kind.FIELD_GET/SET](quickReference.md#location-kinds)\n\n### Advanced Features\n- **JFR Integration** → [Getting Started: JFR](gettingStarted.md#advanced-jfr-integration), [Quick Reference: @Event](quickReference.md#event), [FAQ: JFR](faq.md#jfr-integration)\n- **Sampling** → [Quick Reference: @Sampled](quickReference.md#sampled), [FAQ: Performance](faq.md#btrace-causes-significant-slowdown)\n- **Level Control** → [Quick Reference: @Level](quickReference.md#level)\n- **Aggregations** → [Quick Reference: Aggregation Functions](quickReference.md#aggregation-functions)\n- **Periodic Events** → [Quick Reference: @OnTimer](quickReference.md#ontimer), [@PeriodicEvent](quickReference.md#periodicevent)\n\n### Deployment & Operations\n- **Installation** → [Getting Started: Installation](gettingStarted.md#installation)\n- **Deployment Modes** → [Getting Started: Running BTrace](gettingStarted.md#four-ways-to-run-btrace)\n- **Docker & Containers** → [Getting Started: Containers](gettingStarted.md#btrace-in-containers-and-kubernetes)\n- **Kubernetes** → [Getting Started: K8s](gettingStarted.md#btrace-in-containers-and-kubernetes), [FAQ: Microservices](faq.md#can-i-use-btrace-with-microservices), [Troubleshooting: K8s](troubleshooting.md#kubernetes-and-cloud-deployments)\n- **Performance Tuning** → [FAQ: Performance Impact](faq.md#whats-the-performance-impact-of-btrace), [Troubleshooting: Performance](troubleshooting.md#performance-issues)\n- **Extensions CLI (btracex)** → [Permission Policy](permissionPolicy.md) for allow/deny and quick inspection\n\n### Problem Solving\n- **No Output** → [Troubleshooting: No Output](troubleshooting.md#no-output-from-scripts)\n- **Attachment Fails** → [Troubleshooting: JVM Attachment](troubleshooting.md#jvm-attachment-issues)\n- **Verification Errors** → [Troubleshooting: Verification](troubleshooting.md#script-verification-errors)\n- **Performance Issues** → [Troubleshooting: Performance](troubleshooting.md#performance-issues)\n- **Compatibility** → [Troubleshooting: Compatibility](troubleshooting.md#compatibility-issues)\n\n### Integration\n- **Spring Boot** → [FAQ: Spring Boot](faq.md#can-i-use-btrace-with-spring-boot-applications)\n- **Third-Party Libraries** → [FAQ: Third-Party](faq.md#how-do-i-trace-methods-from-third-party-libraries)\n- **JMX Export** → [Quick Reference: @Export](quickReference.md#export), [FAQ: Monitoring Integration](faq.md#can-i-integrate-btrace-with-monitoring-systems)\n- **Service Mesh** → [FAQ: Service Mesh](faq.md#does-btrace-work-with-service-meshes-istiolinkerd)\n\n### Architecture\n- **Masked JAR** → [Masked JAR Architecture](architecture/MaskedJarArchitecture.md) — single-JAR distribution with classdata masking\n- **v2 Binary Protocol** → [Version 2 Protocol Architecture](architecture/Version2ProtocolArchitecture.md) — custom binary serialization\n- **Extension Framework** → [Extension invokedynamic Bridge](architecture/ExtensionInvokeDynamicBridge.md), [Extension Configuration](architecture/ExtensionConfiguration.md), [Extension Manifest](architecture/ExtensionManifestFormat.md), [Extension Storage](architecture/ExtensionStorageDesign.md)\n- **Instrumentation** → [BTrace Instrumentation Analysis](architecture/BTraceInstrAnalysis.md)\n\n## Sample Scripts\n\nBTrace includes 50+ sample scripts demonstrating real-world use cases:\n- Location: `btrace-dist/src/main/resources/samples/`\n- Examples: File I/O tracking, JDBC monitoring, HTTP requests, memory allocation, thread analysis\n- Browse: [BTrace Samples Directory](../btrace-dist/src/main/resources/samples/)\n\n## External Resources\n\n### Official Resources\n- **GitHub Repository**: [github.com/btraceio/btrace](https://github.com/btraceio/btrace)\n- **Wiki (External)**: [github.com/btraceio/btrace/wiki](https://github.com/btraceio/btrace/wiki/Home)\n- **Maven Plugin**: [github.com/btraceio/btrace-maven](https://github.com/btraceio/btrace-maven)\n- **Releases**: [GitHub Releases](https://github.com/btraceio/btrace/releases/latest)\n\n### Community\n- **Slack**: [btrace.slack.com](http://btrace.slack.com/)\n- **Gitter Chat**: [gitter.im/btraceio/btrace](https://gitter.im/btraceio/btrace)\n- **Issues**: [GitHub Issues](https://github.com/btraceio/btrace/issues)\n- **Discussions**: [GitHub Discussions](https://github.com/btraceio/btrace/discussions)\n\n### Tools & Integrations\n- **VisualVM Plugin**: [visualvm.github.io](https://visualvm.github.io)\n- **JDK Mission Control**: For viewing JFR events created by BTrace\n\n## Contributing\n\nBTrace is an open-source project welcoming contributions. To contribute:\n\n1. Sign the [Oracle Contributor Agreement](https://oca.opensource.oracle.com/)\n2. Read the [Contributing Guidelines](../Readme.md#contributing---important)\n3. Fork the repository and create a pull request\n4. See [Build Instructions](../Readme.md#building-btrace) for development setup\n\n## Version Information\n\n- **Current Version**: Check [GitHub Releases](https://github.com/btraceio/btrace/releases/latest)\n- **Java Compatibility**: Java 8-25\n- **License**: GPLv2 with Classpath Exception\n\n## Documentation Feedback\n\nFound an issue with the documentation? Please:\n- Report it on [GitHub Issues](https://github.com/btraceio/btrace/issues)\n- Tag it with `documentation` label\n- Or submit a pull request with improvements\n\n---\n\n**Ready to get started?** → [Getting Started Guide](gettingStarted.md)\n"
  },
  {
    "path": "docs/Troubleshooting.md",
    "content": "# BTrace Troubleshooting Guide\n\nThis guide helps you diagnose and resolve common BTrace issues.\n\n## Table of Contents\n1. [JVM Attachment Issues](#jvm-attachment-issues)\n2. [Script Compilation Errors](#script-compilation-errors)\n3. [Script Verification Errors](#script-verification-errors)\n4. [No Output from Scripts](#no-output-from-scripts)\n5. [Class/Method Not Found](#classmethod-not-found)\n6. [Performance Issues](#performance-issues)\n7. [Agent Loading Problems](#agent-loading-problems)\n8. [Compatibility Issues](#compatibility-issues)\n9. [Debugging BTrace Scripts](#debugging-btrace-scripts)\n10. [Known Limitations](#known-limitations)\n\n## JVM Attachment Issues\n\n### Unable to attach to target VM\n\n**Error message:**\n```\ncom.sun.tools.attach.AttachNotSupportedException: Unable to attach to target VM\n```\n\n**Causes and solutions:**\n\n1. **Permission mismatch**\n   - **Cause**: BTrace and target JVM run as different users\n   - **Solution**: Run BTrace as the same user as the target JVM\n   ```bash\n   # Check process owner\n   ps aux | grep <PID>\n\n   # Run as correct user\n   sudo -u <username> btrace <PID> script.java\n   ```\n\n2. **Attach mechanism disabled or restricted**\n\n   **For JDK 8-20:**\n   - **Cause**: Target JVM started with `-XX:+DisableAttachMechanism`\n   - **Solution**: Remove this flag and restart the application\n\n   **For JDK 21+ (JEP 451):**\n   - **Cause**: Dynamic agent loading triggers warnings (still works but shows warning)\n   - **Warning message**: `WARNING: A Java agent has been loaded dynamically`\n   - **Solution**: Add `-XX:+EnableDynamicAgentLoading` to target JVM startup to suppress warnings:\n     ```bash\n     java -XX:+EnableDynamicAgentLoading -jar your-application.jar\n     ```\n   - **Note**: In a future JDK release, dynamic agent loading will be **disabled by default**. The `-XX:+EnableDynamicAgentLoading` flag will be required to use BTrace's attach mode.\n   - **Alternative**: Use BTrace in agent mode (attach at startup) instead of dynamic attach:\n     ```bash\n     java -javaagent:/path/to/btrace-agent.jar=script=YourScript.class -jar your-application.jar\n     ```\n\n3. **JRE instead of JDK**\n   - **Cause**: JRE doesn't include attach API tools\n   - **Solution**: Install JDK and ensure `JAVA_HOME` points to it\n   ```bash\n   # Verify JDK installation\n   which javac\n   echo $JAVA_HOME\n   ```\n\n4. **Process in container/namespace**\n   - **Cause**: Target process in Docker/different namespace\n   - **Solution**: Run BTrace in same container/namespace\n   ```bash\n   # For Docker\n   docker exec -it <container> btrace <PID> script.java\n   ```\n\n5. **SELinux/AppArmor restrictions**\n   - **Cause**: Security policies prevent ptrace\n   - **Solution**: Adjust security policies or disable temporarily\n   ```bash\n   # Check SELinux\n   getenforce\n\n   # Temporarily disable (not recommended for production)\n   sudo setenforce 0\n   ```\n\n### Connection refused\n\n**Error message:**\n```\njava.net.ConnectException: Connection refused\n```\n\n**Solutions:**\n- Check if BTrace client port (default 2020) is available\n- Specify different port: `btrace -p 3030 <PID> script.java`\n- Check firewall rules\n\n## Script Compilation Errors\n\n### Compilation failed\n\n**Error message:**\n```\nerror: cannot find symbol\n```\n\n**Common causes:**\n\n1. **Missing imports**\n   ```java\n   // Wrong\n   @BTrace\n   public class MyTrace {\n       @OnMethod(...)\n       public static void handler() {\n           println(\"test\");  // ERROR: cannot find symbol\n       }\n   }\n\n   // Correct\n   import org.openjdk.btrace.core.annotations.*;\n   import static org.openjdk.btrace.core.BTraceUtils.*;\n\n   @BTrace\n   public class MyTrace {\n       @OnMethod(...)\n       public static void handler() {\n           println(\"test\");  // OK\n       }\n   }\n   ```\n\n2. **Wrong package for annotations**\n   ```java\n   // Old (pre-2.0)\n   import com.sun.btrace.annotations.*;\n\n   // New (2.0+)\n   import org.openjdk.btrace.core.annotations.*;\n   ```\n\n3. **Classpath issues**\n   - **Solution**: Add required JARs to classpath\n   ```bash\n   btrace -cp /path/to/lib.jar <PID> script.java\n   ```\n\n## Script Verification Errors\n\n### BTrace script verification failed\n\n**Error message:**\n```\nBTrace : verification failed\n```\n\nBTrace enforces safety restrictions. Common violations:\n\n### 1. Creating new threads\n\n**Wrong:**\n```java\n@OnMethod(...)\npublic static void handler() {\n    new Thread(() -> {}).start();  // ERROR: Cannot create threads\n}\n```\n\n**Right:**\n```java\n@OnMethod(...)\npublic static void handler() {\n    // Use @OnTimer instead\n}\n\n@OnTimer(1000)\npublic static void periodic() {\n    // Executes every second\n}\n```\n\n### 2. Using synchronization\n\n**Wrong:**\n```java\nprivate static Object lock = new Object();\n\n@OnMethod(...)\npublic static void handler() {\n    synchronized (lock) {  // ERROR: Cannot use synchronization\n        // ...\n    }\n}\n```\n\n**Right:**\n```java\nimport static org.openjdk.btrace.core.BTraceUtils.Atomic.*;\n\nprivate static AtomicInteger counter = newAtomicInteger(0);\n\n@OnMethod(...)\npublic static void handler() {\n    incrementAndGet(counter);  // Thread-safe without synchronization\n}\n```\n\n### 3. Loops\n\n**Wrong:**\n```java\n@OnMethod(...)\npublic static void handler() {\n    // ERROR: All loops forbidden in safe mode\n    while (condition) { }\n    for (int i = 0; i < 100; i++) { }\n    do { } while (condition);\n    for (String s : collection) { }\n}\n```\n\n**Right:**\n```java\n@OnMethod(...)\npublic static void handler() {\n    // Use BTraceUtils methods instead\n    // For iteration, use unsafe mode (-u flag) if absolutely necessary\n}\n```\n\n**Note:** ALL loop constructs (`for`, `while`, `do-while`, enhanced `for`) are forbidden in safe mode. Use `-u` (unsafe mode) only in controlled environments if loops are required.\n\n### 4. File I/O operations\n\n**Wrong:**\n```java\n@OnMethod(...)\npublic static void handler() {\n    FileWriter fw = new FileWriter(\"out.txt\");  // ERROR: No file I/O\n}\n```\n\n**Right:**\n```java\n@OnMethod(...)\npublic static void handler() {\n    println(\"Output\");  // Use BTraceUtils output functions\n}\n\n// Or run in unsafe mode\n// btrace -u <PID> script.java\n```\n\n### 5. Calling external methods\n\n**Wrong:**\n```java\n@OnMethod(...)\npublic static void handler() {\n    MyOtherClass.someMethod();  // ERROR: Cannot call external class methods\n    System.out.println(\"test\");  // ERROR: Cannot call System methods\n}\n```\n\n**Right:**\n```java\n@BTrace\npublic class MyTrace {\n    @OnMethod(...)\n    public static void handler() {\n        // Call helper methods within same BTrace class - OK\n        myCustomMethod();\n\n        // Use BTraceUtils methods\n        println(str(timeMillis()));\n    }\n\n    private static void myCustomMethod() {\n        // Helper methods in same class are allowed\n        println(\"Helper method called\");\n    }\n}\n```\n\n**Note:** You CAN call private static methods within the same BTrace class. You CANNOT call methods from external classes (except BTraceUtils).\n\n### 6. Catching exceptions\n\n**Wrong:**\n```java\n@OnMethod(...)\npublic static void handler() {\n    try {\n        // ...\n    } catch (Exception e) {  // ERROR: Cannot catch exceptions\n        // ...\n    }\n}\n```\n\n**Right:**\n```java\n// BTrace handles exceptions automatically\n@OnMethod(...)\npublic static void handler() {\n    // Any exception here is caught and logged by BTrace\n}\n\n// Or use @OnError to track exceptions\n@OnMethod(..., location = @Location(Kind.ERROR))\npublic static void onError(Throwable t) {\n    println(\"Exception: \" + str(t));\n}\n```\n\n## No Output from Scripts\n\n### Script attaches but produces no output\n\n**Diagnostic checklist:**\n\n1. **Verify method is being called**\n   ```java\n   // Add entry point logging\n   @OnMethod(clazz = \"com.example.MyClass\", method = \"<init>\")\n   public static void onInit() {\n       println(\"Constructor called - script is working!\");\n   }\n   ```\n\n2. **Check class and method names**\n   ```bash\n   # Class names are case-sensitive and must be fully qualified\n\n   # Wrong\n   @OnMethod(clazz = \"MyClass\", method = \"process\")\n\n   # Right\n   @OnMethod(clazz = \"com.example.pkg.MyClass\", method = \"process\")\n   ```\n\n3. **Test with wildcard patterns**\n   ```java\n   // Too specific - might not match\n   @OnMethod(clazz = \"com.example.MyClass\", method = \"processData\")\n\n   // Broader - helps identify the issue\n   @OnMethod(clazz = \"/com\\\\.example\\\\..*/\", method = \"/.*/\")\n   public static void catchAll() {\n       println(\"Matched something!\");\n   }\n   ```\n\n4. **Verify regex escaping**\n   ```java\n   // Wrong - dots match any character\n   @OnMethod(clazz = \"/com.example..*/\")\n\n   // Right - dots are escaped\n   @OnMethod(clazz = \"/com\\\\.example\\\\..*/\")\n   ```\n\n5. **Check for inner classes**\n   ```java\n   // Inner classes use $ separator\n   @OnMethod(clazz = \"com.example.Outer$Inner\", method = \"method\")\n   ```\n\n6. **Enable verbose output**\n   ```bash\n   btrace -v <PID> script.java\n   ```\n\n7. **Verify instrumention occurred**\n   ```bash\n   # Dump instrumented classes\n   btrace -d /tmp/btrace-dump <PID> script.java\n\n   # Check if classes were modified\n   ls -la /tmp/btrace-dump/\n   ```\n\n## Class/Method Not Found\n\n### No methods matched\n\n**Error message:**\n```\nNo methods matched for probe: ...\n```\n\n**Solutions:**\n\n1. **Use `jcmd` to find exact class names**\n   ```bash\n   # List loaded classes\n   jcmd <PID> VM.classes | grep -i myclass\n\n   # Find specific methods\n   jcmd <PID> VM.class_hierarchy | grep -A 5 MyClass\n   ```\n\n2. **Verify BTrace is retransforming loaded classes**\n   - BTrace scans ALL already-loaded classes when attaching\n   - It retransforms matching classes via `Instrumentation.retransformClasses()`\n   - It also listens for newly loaded classes\n   - If classes aren't being instrumented, check if they are modifiable:\n   ```bash\n   # Some classes cannot be retransformed (e.g., native methods, JVM internals)\n   # Use -v flag to see which classes are being instrumented\n   btrace -v <PID> script.java\n   ```\n\n3. **Check class loader hierarchy**\n   ```java\n   // Match classes loaded by any classloader\n   @OnMethod(clazz = \"+com.example.MyClass\", method = \"method\")\n   //         ^ plus sign matches subclasses and all classloaders\n   ```\n\n4. **Verify method signature for overloaded methods**\n   ```java\n   // Multiple methods with same name - need signature\n   @OnMethod(clazz = \"com.example.MyClass\",\n            method = \"process\",\n            type = \"void (java.lang.String, int)\")\n   ```\n\n## Performance Issues\n\n### BTrace causes significant slowdown\n\n**Symptoms:**\n- Application becomes unresponsive\n- High CPU usage\n- Increased latency\n\n**Solutions:**\n\n1. **Use sampling**\n   ```java\n   @Sampled(kind = Sampled.Sampler.Adaptive)\n   @OnMethod(...)\n   public static void handler() {\n       // Only executes on sampled invocations\n   }\n   ```\n\n2. **Add level filtering**\n   ```java\n   @OnMethod(clazz = \"...\", enableAt = @Level(\">=2\"))\n   public static void heavyHandler() {\n       // Only active when level >= 2\n   }\n\n   // Control at runtime:\n   // Press Ctrl-C in btrace console, type: level 0\n   ```\n\n3. **Avoid tracing high-frequency methods**\n   ```java\n   // BAD - called millions of times per second\n   @OnMethod(clazz = \"java.lang.String\", method = \"charAt\")\n\n   // GOOD - application-specific methods\n   @OnMethod(clazz = \"com.example.Service\", method = \"handleRequest\")\n   ```\n\n4. **Minimize instrumentation scope**\n   ```java\n   // Too broad - matches thousands of methods\n   @OnMethod(clazz = \"/java\\\\..*/\", method = \"/.*/\")\n\n   // Focused - matches specific target\n   @OnMethod(clazz = \"com.example.Service\", method = \"slowMethod\")\n   ```\n\n5. **Reduce output volume**\n   ```java\n   // Bad - prints every invocation\n   @OnMethod(...)\n   public static void handler() {\n       println(\"Called\");\n   }\n\n   // Better - periodic summary\n   private static AtomicInteger count = newAtomicInteger(0);\n\n   @OnMethod(...)\n   public static void handler() {\n       incrementAndGet(count);\n   }\n\n   @OnTimer(5000)\n   public static void report() {\n       println(\"Calls in last 5s: \" + str(get(count)));\n       set(count, 0);\n   }\n   ```\n\n6. **Use aggregations instead of individual logs**\n   ```java\n   private static Aggregation duration =\n       Aggregations.newAggregation(AggregationFunction.QUANTIZE);\n\n   @OnMethod(..., location = @Location(Kind.RETURN))\n   public static void onReturn(@Duration long d) {\n       Aggregations.addToAggregation(duration, d / 1000000);\n   }\n\n   @OnTimer(10000)\n   public static void printStats() {\n       Aggregations.printAggregation(\"Durations\", duration);\n       Aggregations.clearAggregation(duration);\n   }\n   ```\n\n## Agent Loading Problems\n\n### Agent JAR not found\n\n**Error message:**\n```\nError opening zip file or JAR manifest missing : /path/to/btrace-agent.jar\n```\n\n**Solutions:**\n```bash\n# Verify JAR exists\nls -la /path/to/btrace-agent.jar\n\n# Use absolute path\njava -javaagent:/absolute/path/to/btrace-agent.jar=script=Script.class MyApp\n\n# Or set BTRACE_HOME\nexport BTRACE_HOME=/path/to/btrace\njava -javaagent:$BTRACE_HOME/libs/btrace-agent.jar=script=Script.class MyApp\n```\n\n### Script class not found in agent mode\n\n**Error message:**\n```\nClassNotFoundException: MyTrace\n```\n\n**Solutions:**\n```bash\n# Specify absolute path to script\njava -javaagent:btrace-agent.jar=script=/absolute/path/MyTrace.class MyApp\n\n# Or add to classpath\njava -javaagent:btrace-agent.jar=script=MyTrace.class \\\n     -cp /path/to/scripts:app.jar MyApp\n```\n\n## Compatibility Issues\n\n### Java Version Mismatch\n\n**Error message:**\n```\nUnsupportedClassVersionError\n```\n\n**Solutions:**\n- Ensure BTrace supports your Java version (BTrace supports Java 8+)\n- Compile scripts with target version matching JVM\n- Check `JAVA_HOME` points to correct version\n\n### Module System Issues (Java 9+)\n\n**Error message:**\n```\nIllegalAccessError: class X cannot access class Y\n```\n\n**Solutions:**\n```bash\n# Add required --add-opens flags\nbtrace --add-opens java.base/jdk.internal.misc=ALL-UNNAMED <PID> script.java\n\n# Or add to target JVM startup\njava --add-opens java.base/java.lang=ALL-UNNAMED \\\n     --add-opens java.base/jdk.internal.misc=ALL-UNNAMED \\\n     MyApp\n```\n\n### Old Script Syntax\n\n**Error:**\nScripts written for BTrace 1.x fail with 2.x\n\n**Solution:**\nUpdate imports:\n```java\n// Old (1.x)\nimport com.sun.btrace.annotations.*;\nimport static com.sun.btrace.BTraceUtils.*;\n\n// New (2.x)\nimport org.openjdk.btrace.core.annotations.*;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n```\n\n## Debugging BTrace Scripts\n\n### Enable verbose logging\n\n```bash\nbtrace -v <PID> script.java\n```\n\n### Dump instrumented classes\n\n```bash\nbtrace -d /tmp/btrace-classes <PID> script.java\n```\n\nThen examine with:\n```bash\njavap -c /tmp/btrace-classes/com/example/MyClass.class\n```\n\n### Print diagnostic info\n\n```java\n@OnMethod(clazz = \"com.example.MyClass\", method = \"myMethod\")\npublic static void handler(@ProbeClassName String clazz,\n                          @ProbeMethodName String method) {\n    println(\"Class: \" + clazz);\n    println(\"Method: \" + method);\n    println(\"Thread: \" + threadName());\n    println(\"Stack:\");\n    jstack(5);  // Print 5 stack frames\n}\n```\n\n### Test incrementally\n\nStart simple and add complexity:\n\n```java\n// Step 1: Verify attachment\n@OnTimer(1000)\npublic static void heartbeat() {\n    println(\"BTrace alive\");\n}\n\n// Step 2: Verify class matching\n@OnMethod(clazz = \"com.example.MyClass\", method = \"/.*/\")\npublic static void anyMethod() {\n    println(\"Matched\");\n}\n\n// Step 3: Add specific logic\n@OnMethod(clazz = \"com.example.MyClass\", method = \"specificMethod\")\npublic static void specific(String arg) {\n    println(\"Arg: \" + arg);\n}\n```\n\n## Kubernetes and Cloud Deployments\n\n### Finding Process ID in Pods\n\n**Problem:** Need to find Java process ID inside a pod\n\n**Solutions:**\n```bash\n# List Java processes in pod\nkubectl exec <pod-name> -- jps\n\n# Or use ps\nkubectl exec <pod-name> -- ps aux | grep java\n\n# For multi-container pods, specify container\nkubectl exec <pod-name> -c <container-name> -- jps\n```\n\n### Multi-Container Pod Considerations\n\n**Problem:** Cannot attach to process in different container\n\n**Solution:**\nKubernetes pods with multiple containers have separate process namespaces by default.\n\n```yaml\n# Enable process namespace sharing\napiVersion: v1\nkind: Pod\nmetadata:\n  name: myapp\nspec:\n  shareProcessNamespace: true  # Required for cross-container attachment\n  containers:\n  - name: app\n    image: myapp:latest\n  - name: btrace-sidecar\n    image: btrace:latest\n```\n\n**Note:** With `shareProcessNamespace: true`, all containers can see each other's processes.\n\n### Port Conflicts in Pods\n\n**Problem:** BTrace fails with port already in use\n\n**Error:**\n```\njava.net.BindException: Address already in use\n```\n\n**Cause:** BTrace uses port 2020 by default; multiple BTrace instances or port conflicts\n\n**Solutions:**\n```bash\n# Use different port\nkubectl exec <pod> -- btrace -p 3030 <PID> script.java\n\n# Check port usage\nkubectl exec <pod> -- netstat -an | grep 2020\n```\n\n### Security Policies and RBAC\n\n**Problem:** Pod Security Policy blocks BTrace attachment\n\n**Error:**\n```\nOperation not permitted\n```\n\n**Common causes:**\n\n1. **Pod Security Standards** (PSP replacement in K8s 1.25+):\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: myapp\nspec:\n  securityContext:\n    # May need to adjust based on policy\n    runAsNonRoot: true\n    capabilities:\n      add:\n      - SYS_PTRACE  # Required for process attachment\n```\n\n2. **SELinux/AppArmor**:\n```bash\n# Check if SELinux is blocking\nkubectl exec <pod> -- getenforce\n\n# Check AppArmor profile\nkubectl exec <pod> -- cat /proc/self/attr/current\n```\n\n**Solutions:**\n- Add `SYS_PTRACE` capability if allowed by security policy\n- Run as same user as target JVM\n- Adjust security context constraints (OpenShift)\n\n### JDK Not Available in Container\n\n**Problem:** BTrace requires JDK but only JRE in container\n\n**Error:**\n```\nError: tools.jar not found\n```\n\n**Solutions:**\n\n**Option 1: Use JDK base image**\n```dockerfile\n# Instead of JRE\nFROM openjdk:11-jre\n# Use JDK\nFROM bellsoft/liberica-openjdk-debian:11-cds\n```\n\n**Option 2: Install JDK in running pod** (temporary)\n```bash\nkubectl exec <pod> -- apt-get update && apt-get install -y openjdk-11-jdk\n```\n\n**Option 3: Sidecar with JDK**\n```yaml\nspec:\n  shareProcessNamespace: true\n  containers:\n  - name: app\n    image: myapp-jre:latest  # Can use JRE\n  - name: btrace\n    image: bellsoft/liberica-openjdk-debian:11-cds     # Sidecar has JDK\n```\n\n### Service Mesh Compatibility\n\n**Istio/Linkerd:**\n\nBTrace works with service meshes but some considerations apply:\n\n**Traffic Interception:**\n- Service mesh sidecars don't interfere with BTrace (different layer)\n- BTrace communication port (2020) not intercepted by mesh\n\n**mTLS:**\n- BTrace uses local socket communication (not HTTP)\n- mTLS between services doesn't affect BTrace\n\n**Resource Limits:**\n```yaml\n# BTrace overhead may trigger limits\nresources:\n  requests:\n    cpu: \"100m\"\n    memory: \"128Mi\"\n  limits:\n    cpu: \"500m\"      # Increase if BTrace causes throttling\n    memory: \"512Mi\"   # Increase if needed\n```\n\n### ConfigMap for BTrace Scripts\n\n**Pattern:** Store scripts in ConfigMap for easy distribution\n\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: btrace-scripts\ndata:\n  TraceMethod.java: |\n    import org.openjdk.btrace.core.annotations.*;\n    import static org.openjdk.btrace.core.BTraceUtils.*;\n\n    @BTrace\n    // Classname 'TraceMethod' must correspond to the file name 'TraceMethod.java'\n    public class TraceMethod {\n        @OnMethod(clazz = \"com.example.Service\", method = \"process\")\n        public static void onProcess() {\n            println(\"Method called\");\n        }\n    }\n---\napiVersion: v1\nkind: Pod\nspec:\n  containers:\n  - name: app\n    image: myapp:latest\n    volumeMounts:\n    - name: scripts\n      mountPath: /btrace-scripts\n  volumes:\n  - name: scripts\n    configMap:\n      name: btrace-scripts\n```\n\nUsage:\n```bash\nkubectl exec <pod> -- btrace <PID> /btrace-scripts/TraceMethod.java\n```\n\n### Batch Tracing Across Pods\n\n**Pattern:** Trace all pods in a deployment\n\n```bash\n#!/bin/bash\n# trace-deployment.sh\n\nDEPLOYMENT=$1\nSCRIPT=$2\n\n# Get all pod names for deployment\nPODS=$(kubectl get pods -l app=$DEPLOYMENT -o jsonpath='{.items[*].metadata.name}')\n\nfor POD in $PODS; do\n  echo \"Attaching to $POD...\"\n  kubectl exec $POD -- btrace 1 $SCRIPT &\ndone\n\nwait\necho \"All traces complete\"\n```\n\nUsage:\n```bash\n./trace-deployment.sh myapp /tmp/trace.java\n```\n\n### Persistent Tracing with StatefulSets\n\n**Issue:** BTrace doesn't persist across pod restarts\n\n**Solutions:**\n\n1. **Store output in persistent volume:**\n```bash\nkubectl exec <pod> -- btrace -o /data/trace.log <PID> script.java\n```\n\n2. **Stream to external system:**\n```java\n// Use StatSD integration\n@OnMethod(...)\npublic static void handler() {\n    Statsd.send(\"metric.name\", value);\n}\n```\n\n3. **Agent mode in pod spec:**\n```yaml\nspec:\n  containers:\n  - name: app\n    image: myapp:latest\n    env:\n    - name: JAVA_TOOL_OPTIONS\n      value: \"-javaagent:/opt/btrace/lib/btrace-agent.jar=script=/scripts/trace.class\"\n```\n\n### Cloud-Specific Issues\n\n**AWS EKS:**\n- No specific issues; standard K8s patterns apply\n- Use same region for kubectl access\n\n**Google GKE:**\n- GKE Autopilot: May restrict `SYS_PTRACE` capability\n- Use standard GKE for full BTrace support\n\n**Azure AKS:**\n- No specific issues; standard K8s patterns apply\n- Ensure node has sufficient resources\n\n**OpenShift:**\n- Security Context Constraints (SCC) may be stricter\n- May need to add SCC for SYS_PTRACE:\n```bash\noc adm policy add-scc-to-user anyuid -z default\n```\n\nFor more K8s deployment patterns, see [Getting Started: K8s](gettingStarted.md#btrace-in-containers-and-kubernetes) and [FAQ: Microservices](faq.md#can-i-use-btrace-with-microservices).\n\n## Known Limitations\n\n### Cannot instrument\n\n**Native methods:**\n- Methods implemented in native code cannot be instrumented (JVM limitation)\n\n**Sensitive classes (to avoid infinite recursion):**\n- Core classes BTrace depends on: `java.lang.Object`, `String`, `ThreadLocal`, `Integer`, `Number`\n- Package prefixes: `java.lang.instrument.*`, `java.lang.invoke.*`, `java.lang.ref.*`\n- Lock classes: `java.util.concurrent.locks.LockSupport`, `AbstractQueuedSynchronizer`, etc.\n- JDK internals: `jdk.internal.*`, `sun.invoke.*`\n- BTrace itself: `org.openjdk.btrace.*`\n\n**Classes annotated with @BTrace** (BTrace scripts themselves)\n\n**Note:** Classes already transformed by other agents CAN be retransformed. Boot classpath and JDK classes CAN be instrumented (except the sensitive classes listed above).\n\n### Cannot trace\n- Very early VM initialization (use agent mode instead of attach mode)\n- Class loading before agent initialization\n- JVM shutdown sequence (partially)\n\n### Platform-specific issues\n\n**Windows:**\n- Attach API may require admin privileges\n- Path separators: use `\\\\` or `/`\n\n**macOS:**\n- SIP (System Integrity Protection) may block attachment\n- Disable for debugging: `csrutil disable` (not recommended for production)\n\n**Linux:**\n- Some distros have ptrace restrictions in `/proc/sys/kernel/yama/ptrace_scope`\n- Set to 0 to allow: `echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope`\n\n## Getting Help\n\nIf issues persist:\n\n1. **Check BTrace version**\n   ```bash\n   btrace --version\n   ```\n\n2. **Search existing issues**\n   - [GitHub Issues](https://github.com/btraceio/btrace/issues)\n\n3. **Provide details when asking for help:**\n   - BTrace version\n   - Java version (`java -version`)\n   - OS and version\n   - Complete error message\n   - Minimal reproducing script\n   - Target application details\n\n4. **Community channels:**\n   - Slack: [btrace.slack.com](http://btrace.slack.com/)\n   - Gitter: [gitter.im/btraceio/btrace](https://gitter.im/btraceio/btrace)\n   - GitHub Issues: [github.com/btraceio/btrace/issues](https://github.com/btraceio/btrace/issues)\n\n## See Also\n\n- **[Documentation Hub](Readme.md)** - Complete documentation map and learning paths\n- **[Getting Started Guide](gettingStarted.md)** - Installation, first script, and quick start\n- **[Quick Reference](quickReference.md)** - Annotation and API cheat sheet\n- **[BTrace Tutorial](btraceTutorial.md)** - Progressive lessons covering all features\n- **[FAQ](faq.md)** - Common questions and best practices\n"
  },
  {
    "path": "docs/architecture/BTraceInstrAnalysis.md",
    "content": "# BTrace Instrumentation Engine - Analysis & Improvement Proposals\n\n**Document Version**: 2.0\n**Date**: 2025-12-22 (Updated)\n**Original Analysis**: 2025-12-20\n**Analysis Scope**: btrace-instr module correctness, performance, and architecture\n\n## Status Update (2025-12-22)\n\n**Implementation Complete**: 10 of 14 issues resolved\n\n| Priority | Category | Fixed | Remaining |\n|----------|----------|-------|-----------|\n| P0 | Critical Correctness | 2/2 ✅ | 0 |\n| P1 | High-Impact Performance | 5/5 ✅ | 0 |\n| P2 | Allocation Pressure | 1/2 | 1 |\n| P3 | Code Quality | 1/3 | 2 |\n| P4 | Test Coverage | 0/1 | 1 |\n\n### Completed Fixes\n\nAll critical (P0) and high-impact performance (P1) issues have been resolved:\n\n1. ✅ **Issue 1**: MethodTracker copy bug (commit: b3c59fb0)\n2. ✅ **Issue 2**: Magic return value 0xFFFFFFFF (commit: d05c3bd5)\n3. ✅ **Issue 3**: Handler bytecode caching (commit: e054746f)\n4. ✅ **Issue 4**: Pattern compilation caching (commit: cc7cfcbe)\n5. ✅ **Issue 5**: CallGraph HashMap index (commit: 5e2c070f)\n6. ✅ **Issue 6**: String transformation caching (commit: fa87e17f)\n7. ✅ **Issue 7**: Test O(n²) allocation (commit: 9f35f2d2)\n8. ✅ **Issue 9**: VariableMapper allocation (commit: 3a3f53d8)\n9. ✅ **Issue 10**: Thread.dumpStack() removal (commit: d05c3bd5)\n10. ✅ **InstrumentationException consolidation**: 5 additional RuntimeException instances unified (commit: d05c3bd5)\n\n### Measured Impact\n\n**Performance Improvements:**\n- 20-30% faster class transformation (pattern & handler caching)\n- 40-60% reduction in memory allocations (optimized data structures)\n- Handler lookup: ~1ms → ~100ns (99.9% cache hit rate)\n\n**Correctness:**\n- Eliminated data corruption bug in MethodTracker\n- Replaced magic values with proper exception handling\n- Added detailed error messages with context\n\n### Remaining Work\n\n**P2-P4 Issues** (Lower Priority):\n- Issue 8: InstrumentingMethodVisitor lazy copy-on-read\n- Issue 11: Raw types in test code\n- Issue 12: Test duplication investigation\n- Issue 13: Edge case test coverage\n\n## Executive Summary\n\nThis document presents a comprehensive analysis of the btrace-instr module, identifying critical issues that affect correctness, performance, and maintainability. The analysis was conducted through systematic exploration of the instrumentation engine, handler management, and test infrastructure.\n\n### Original Findings (2025-12-20)\n\n**14 issues identified across 3 priority levels:**\n\n| Priority | Category | Count | Impact |\n|----------|----------|-------|---------|\n| P0 | Critical Correctness | 2 | Data corruption, type safety violations |\n| P1 | High-Impact Performance | 5 | 20-30% performance improvement potential |\n| P2-P4 | Architectural Debt | 7 | Maintainability, test coverage, code quality |\n\n### Impact Assessment\n\n- **Correctness**: One critical data corruption bug in MethodTracker affecting adaptive sampling\n- **Performance**: Multiple hot-path issues causing unnecessary allocations and repeated computation\n- **Maintainability**: Magic values, debug code in production, missing test coverage\n\n### Recommended Actions\n\nFixing **P0+P1 issues (estimated 3 days)** will provide highest value:\n- Eliminates data corruption bug\n- 20-30% performance improvement in class transformation\n- 40-60% reduction in memory pressure during instrumentation\n\n---\n\n## Part 1: Critical Correctness Issues (P0)\n\n### Issue 1: MethodTracker Array Copy Bug\n\n**Priority**: P0 (Critical)\n**File**: `btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodTracker.java:62`\n**Type**: Data Corruption\n\n#### Problem Description\n\nThe `registerCounter()` method contains a copy-paste error that corrupts the `origMeans` array during resize operations:\n\n```java\npublic static synchronized void registerCounter(int methodId, int mean) {\n  if (counters.length <= methodId) {\n    int newLen = methodId * 2;\n    counters = Arrays.copyOf(counters, newLen);\n    rLocks = Arrays.copyOf(rLocks, newLen);\n    means = Arrays.copyOf(means, newLen);\n    origMeans = Arrays.copyOf(means, newLen);     // LINE 62 - BUG: copies 'means' instead of 'origMeans'\n    samplers = Arrays.copyOf(samplers, newLen);\n    tsArray = Arrays.copyOf(tsArray, newLen);\n  }\n  // ...\n}\n```\n\n#### Impact Analysis\n\n**What Goes Wrong**:\n1. When method ID > 50, arrays need resizing\n2. `origMeans` is copied from `means` (current adjusted values) instead of `origMeans` (original values)\n3. Adaptive sampling loses baseline - all subsequent adjustments are based on wrong values\n4. Sampling rates become incorrect for method IDs > 50\n5. Silent failure - no exceptions, just wrong behavior\n\n**Affected Code Paths**:\n- `hitAdaptive()` (line 130-158) - uses `origMeans[methodId]` to adjust sampling rate\n- `hitTimedAdaptive()` (line 168-196) - same issue with timing\n\n**Real-World Impact**:\n- Applications with >50 instrumented methods will have incorrect sampling behavior\n- Adaptive sampling becomes ineffective (defeats the purpose of the feature)\n- Silent - users won't notice until they analyze sampling statistics\n\n#### Proposed Solution\n\n**Fix** (1-line change):\n```java\norigMeans = Arrays.copyOf(origMeans, newLen);  // Correct: copy origMeans, not means\n```\n\n**Verification**:\n```java\n@Test\nvoid testRegisterCounterPreservesOrigMeans() {\n  // Register 100 method IDs to trigger resize\n  for (int i = 0; i < 100; i++) {\n    MethodTracker.registerCounter(i, 1000 + i);\n  }\n\n  // Verify origMeans preserved correctly\n  // (Requires adding test accessor for origMeans array)\n  for (int i = 0; i < 100; i++) {\n    assertEquals(1000 + i, getOrigMean(i), \"Original mean corrupted for method \" + i);\n  }\n}\n```\n\n#### Risk Assessment\n\n- **Fix Complexity**: Trivial (1 line)\n- **Testing Effort**: Low (unit test to verify)\n- **Risk**: Minimal (obvious bug, clear fix)\n- **Breaking Changes**: None (fixes broken behavior)\n\n---\n\n### Issue 2: Magic Return Value (0xFFFFFFFF)\n\n**Priority**: P0 (Critical)\n**File**: `btrace-instr/src/main/java/org/openjdk/btrace/instr/VariableMapper.java:136,139`\n**Type**: Type Safety Violation\n\n#### Problem Description\n\nThe `map()` method uses sentinel value `0xFFFFFFFF` to signal \"invalid mapping\" instead of proper error handling:\n\n```java\nprivate int map(int var, int[] currentMapping) {\n  // ... snip ...\n  int offset = (var - argsSize);\n\n  if (offset >= 0) {\n    if (currentMapping.length <= offset) {\n      return 0xFFFFFFFF;  // LINE 136 - MAGIC VALUE\n    }\n    int newVar = currentMapping[offset];\n    return (newVar & REMAP_FLAG) != 0 ? unmask(newVar) : 0xFFFFFFFF;  // LINE 139 - MAGIC VALUE\n  }\n  return var;\n}\n```\n\n**Callers Check Magic Value**:\n```java\n// InstrumentingMethodVisitor.java:1055\nint origVar = vMapper.map(var, label);\nif (origVar != 0xFFFFFFFF) {  // Checking for magic value\n  // ... use origVar ...\n}\n\n// InstrumentingMethodVisitor.java:1075\nint mappedVar = vMapper.map(v.index, label);\nif (mappedVar != 0xFFFFFFFF) {\n  // ... use mappedVar ...\n}\n```\n\n#### Impact Analysis\n\n**Type Safety Issues**:\n- Conflates data (variable index) with control flow (error signal)\n- Return type `int` can't distinguish between valid value and error\n- Callers must remember to check for magic value\n- Easy to forget check and propagate invalid value\n\n**Failure Modes**:\n1. If caller forgets to check → invalid variable index propagates\n2. If valid mapping happens to be 0xFFFFFFFF → incorrectly treated as error\n3. Debugging is harder - what does 0xFFFFFFFF mean in context?\n\n#### Proposed Solutions\n\n**Option A: Exception-based (Recommended)**\n\nBest for truly exceptional conditions (unmapped variables should not occur in correct code).\n\n```java\npublic int map(int var) {\n  return map(var, mapping);\n}\n\npublic int map(int var, Label label) {\n  return map(var, labelMappings.getOrDefault(label, mapping));\n}\n\nprivate int map(int var, int[] currentMapping) {\n  if (((var & REMAP_FLAG) != 0)) {\n    return unmask(var);\n  }\n\n  int offset = (var - argsSize);\n\n  if (offset >= 0) {\n    if (currentMapping.length <= offset) {\n      throw new IllegalStateException(\n        String.format(\"Unmapped variable offset %d (var=%d, argsSize=%d)\", offset, var, argsSize));\n    }\n    int newVar = currentMapping[offset];\n    if ((newVar & REMAP_FLAG) == 0) {\n      throw new IllegalStateException(\n        String.format(\"Variable not remapped: var=%d, offset=%d\", var, offset));\n    }\n    return unmask(newVar);\n  }\n  return var;\n}\n```\n\n**Caller Updates**:\n```java\n// InstrumentingMethodVisitor.java:1055\ntry {\n  int origVar = vMapper.map(var, label);\n  // ... use origVar (always valid) ...\n} catch (IllegalStateException e) {\n  log.debug(\"Variable not mapped: {}\", var, e);\n  // ... handle unmapped variable ...\n}\n```\n\n**Option B: OptionalInt (Alternative)**\n\nBest for nullable semantics where \"no mapping\" is a valid state.\n\n```java\npublic OptionalInt tryMap(int var) {\n  return tryMap(var, mapping);\n}\n\npublic OptionalInt tryMap(int var, Label label) {\n  return tryMap(var, labelMappings.getOrDefault(label, mapping));\n}\n\nprivate OptionalInt tryMap(int var, int[] currentMapping) {\n  if (((var & REMAP_FLAG) != 0)) {\n    return OptionalInt.of(unmask(var));\n  }\n\n  int offset = (var - argsSize);\n\n  if (offset >= 0) {\n    if (currentMapping.length <= offset) {\n      return OptionalInt.empty();  // No mapping\n    }\n    int newVar = currentMapping[offset];\n    if ((newVar & REMAP_FLAG) == 0) {\n      return OptionalInt.empty();  // Not remapped\n    }\n    return OptionalInt.of(unmask(newVar));\n  }\n  return OptionalInt.of(var);\n}\n```\n\n**Caller Updates**:\n```java\n// InstrumentingMethodVisitor.java:1055\nOptionalInt origVar = vMapper.tryMap(var, label);\nif (origVar.isPresent()) {\n  // ... use origVar.getAsInt() ...\n} else {\n  // ... handle unmapped variable ...\n}\n```\n\n#### Recommendation\n\n**Use Option A (Exception-based)** because:\n1. Unmapped variables indicate a bug in instrumentation logic (exceptional condition)\n2. Simpler caller code (no need to check Optional everywhere)\n3. Fail-fast behavior helps catch bugs early\n4. Aligns with existing error handling patterns in the codebase\n\n#### Implementation Plan\n\n1. Add exception-based `map()` method\n2. Update all call sites (InstrumentingMethodVisitor:1055, 1075, others)\n3. Add tests for error cases\n4. Remove magic value constants and checks\n\n#### Risk Assessment\n\n- **Fix Complexity**: Medium (4 hours to update all call sites)\n- **Testing Effort**: Medium (verify all error paths)\n- **Risk**: Medium (changes error handling contract, requires careful testing)\n- **Breaking Changes**: Internal API only (no external impact)\n\n---\n\n## Part 2: High-Impact Performance Issues (P1)\n\n### Issue 3: Handler Bytecode Regeneration — RESOLVED\n\n**Status**: Obsolete. The root cause (per-linkage bytecode regeneration via `CopyingVisitor`)\nwas eliminated when handler dispatch moved to direct `MethodHandle` resolution. Handler\nmethods are now resolved directly against the probe class via\n`MethodHandles.publicLookup().findStatic()` from `HandlerRepositoryImpl.resolveHandler()`,\nand dispatched by `IndyDispatcher.bootstrap()`. No handler bytecode is generated or copied\nat runtime. `CopyingVisitor` has been deleted.\n\nThe sections below describe the *old* design and are retained purely for historical\ncontext. Do not use them as a reference for current code.\n\n---\n\n#### Historical Problem Description\n\nThe `getProbeHandler()` method regenerated identical bytecode on **every invokedynamic\nlinkage** (Java 15+ only). This was called from `Indy.bootstrap()` during invokedynamic\ncallsite linking.\n\n**Current Code Flow**:\n```java\npublic static byte[] getProbeHandler(\n    String callerName, String probeName, String handlerName, String handlerDesc) {\n\n  // LINE 45 - NEW ALLOCATION (every call)\n  DebugSupport debugSupport = new DebugSupport(SharedSettings.GLOBAL);\n\n  BTraceProbe probe = probeMap.get(probeName);\n\n  // LINE 47 - NEW ALLOCATION (every call)\n  ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);\n\n  String handlerClassName = callerName.replace('.', '/') + \"$\" + probeName.replace('/', '_');\n\n  // LINE 50 - NEW ALLOCATION (every call - anonymous class instance)\n  ClassVisitor visitor =\n      new CopyingVisitor(handlerClassName, true, writer) {\n        @Override\n        protected String getMethodName(String name) {\n          int idx = name.lastIndexOf(\"$\");\n          if (idx > -1) {\n            return name.substring(idx + 1);\n          }\n          return name;\n        }\n      };\n\n  probe.copyHandlers(visitor);  // Generates bytecode\n  byte[] data = writer.toByteArray();  // LINE 63 - Same bytes every time\n\n  // ... dump logic ...\n\n  return data;\n}\n```\n\n#### Performance Impact\n\n**Allocation Profile** (per call):\n- 1× DebugSupport instance (~200 bytes)\n- 1× ClassWriter instance (~1KB + internal buffers)\n- 1× Anonymous CopyingVisitor instance (~500 bytes)\n- 1× byte[] for bytecode (~5-20KB)\n- **Total: ~7-22KB allocated per call**\n\n**Frequency**:\n- Called once per invokedynamic callsite (Java 15+)\n- Typical BTrace probe: 10-100 callsites\n- Under load: 1000+ calls/second possible\n- **Waste: 7-22MB/sec of temporary allocations**\n\n**Key Insight**: Output is **deterministic**\n- Same inputs → same bytecode every time\n- Perfect candidate for caching\n\n#### Proposed Solution: Bytecode Caching\n\n```java\npublic final class HandlerRepositoryImpl {\n  private static final Logger log = LoggerFactory.getLogger(HandlerRepositoryImpl.class);\n\n  private static final Map<String, BTraceProbe> probeMap = new ConcurrentHashMap<>();\n\n  // NEW: Cache for generated handler bytecode\n  private static final Map<String, byte[]> handlerBytecodeCache = new ConcurrentHashMap<>();\n\n  // ... existing static initializer ...\n\n  public static void registerProbe(BTraceProbe probe) {\n    probeMap.put(probe.getClassName(true), probe);\n  }\n\n  public static void unregisterProbe(BTraceProbe probe) {\n    String probeName = probe.getClassName(true);\n    probeMap.remove(probeName);\n\n    // NEW: Invalidate cache entries for this probe\n    String probePrefix = probeName + \"#\";\n    handlerBytecodeCache.keySet().removeIf(key -> key.startsWith(probePrefix));\n  }\n\n  public static byte[] getProbeHandler(\n      String callerName, String probeName, String handlerName, String handlerDesc) {\n\n    // NEW: Cache key from handler signature\n    String cacheKey = probeName + \"#\" + handlerName + handlerDesc;\n\n    // NEW: Check cache first (lock-free read)\n    return handlerBytecodeCache.computeIfAbsent(cacheKey, k -> {\n      // EXISTING: Generation logic (only runs on cache miss)\n      DebugSupport debugSupport = new DebugSupport(SharedSettings.GLOBAL);\n      BTraceProbe probe = probeMap.get(probeName);\n      ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);\n\n      String handlerClassName = callerName.replace('.', '/') + \"$\" + probeName.replace('/', '_');\n      ClassVisitor visitor =\n          new CopyingVisitor(handlerClassName, true, writer) {\n            @Override\n            protected String getMethodName(String name) {\n              int idx = name.lastIndexOf(\"$\");\n              return idx > -1 ? name.substring(idx + 1) : name;\n            }\n          };\n\n      probe.copyHandlers(visitor);\n      byte[] data = writer.toByteArray();\n\n      // Dump logic (still runs, useful for debugging)\n      if (debugSupport.isDumpClasses()) {\n        try {\n          String handlerPath =\n              debugSupport.getDumpClassDir() + \"/\" + handlerClassName.replace('/', '_') + \".class\";\n          log.debug(\"BTrace INDY handler dumped: {}\", handlerPath);\n          Files.write(Paths.get(handlerPath), data, StandardOpenOption.CREATE);\n        } catch (Throwable e) {\n          log.debug(\"Failed to dump BTrace INDY handler\", e);\n        }\n      }\n\n      return data;\n    });\n  }\n}\n```\n\n#### Benefits\n\n**Performance Gains**:\n- **First call**: Same cost as before (cache miss)\n- **Subsequent calls**: O(1) HashMap lookup only (~100ns vs ~1ms)\n- **Steady-state**: 99.99% cache hit rate (deterministic output)\n- **Memory savings**: 7-22MB/sec allocation eliminated under load\n\n**Memory Cost**:\n- Cache stores generated bytecode (~5-20KB per unique handler)\n- Typical application: 10-50 unique handlers = 50KB-1MB total\n- Trade-off: 1MB memory for 10MB/sec allocation reduction\n\n**Correctness**:\n- Cache invalidated on `unregisterProbe()` (probe updates are rare)\n- `ConcurrentHashMap` provides thread-safe access\n- `computeIfAbsent()` ensures single generation per key\n\n#### Testing Strategy\n\n```java\n@Test\nvoid testHandlerBytecodeCache() {\n  // Register a probe\n  BTraceProbe probe = createTestProbe(\"TestProbe\");\n  HandlerRepositoryImpl.registerProbe(probe);\n\n  // First call - should generate bytecode\n  byte[] handler1 = HandlerRepositoryImpl.getProbeHandler(\n    \"com.example.Test\", \"TestProbe\", \"onMethod\", \"()V\");\n\n  // Second call - should return cached bytecode\n  byte[] handler2 = HandlerRepositoryImpl.getProbeHandler(\n    \"com.example.Test\", \"TestProbe\", \"onMethod\", \"()V\");\n\n  // Verify same bytecode returned (cached)\n  assertSame(handler1, handler2, \"Should return cached bytecode\");\n\n  // Unregister probe - should invalidate cache\n  HandlerRepositoryImpl.unregisterProbe(probe);\n\n  // Re-register and call again - should regenerate\n  HandlerRepositoryImpl.registerProbe(probe);\n  byte[] handler3 = HandlerRepositoryImpl.getProbeHandler(\n    \"com.example.Test\", \"TestProbe\", \"onMethod\", \"()V\");\n\n  // Verify new bytecode generated (cache was invalidated)\n  assertNotSame(handler1, handler3, \"Should regenerate after unregister\");\n}\n```\n\n#### Risk Assessment\n\n- **Fix Complexity**: Low (3 hours)\n- **Testing Effort**: Low (cache hit/miss, invalidation)\n- **Risk**: Low (purely additive cache layer, no behavior change)\n- **Breaking Changes**: None\n\n---\n\n### Issue 4: Pattern Compilation in Hot Path\n\n**Priority**: P1 (High Performance Impact)\n**File**: `btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbeSupport.java:103,112`\n**Type**: Repeated Computation\n\n#### Problem Description\n\nThe `getApplicableHandlers()` method compiles regex patterns **on every class transformation**:\n\n```java\nCollection<OnMethod> getApplicableHandlers(BTraceClassReader cr) {\n  Collection<OnMethod> applicables = new ArrayList<>(onMethods.size());\n  String targetName = cr.getJavaClassName();\n\n  outer:\n  for (OnMethod om : onMethods) {\n    String probeClass = om.getClazz();\n    // ... exact match check ...\n\n    // LINE 102-107 - PATTERN COMPILED EVERY TIME\n    if (om.isClassRegexMatcher() && !om.isClassAnnotationMatcher()) {\n      Pattern p = Pattern.compile(probeClass);  // EXPENSIVE\n      if (p.matcher(targetName).matches()) {\n        applicables.add(om);\n        continue;\n      }\n    }\n\n    // LINE 109-118 - PATTERN COMPILED AGAIN\n    if (om.isClassAnnotationMatcher()) {\n      Collection<String> annoTypes = cr.getAnnotationTypes();\n      if (om.isClassRegexMatcher()) {\n        Pattern p = Pattern.compile(probeClass);  // EXPENSIVE (duplicate)\n        for (String annoType : annoTypes) {\n          if (p.matcher(annoType).matches()) {\n            applicables.add(om);\n            continue outer;\n          }\n        }\n      }\n      // ...\n    }\n    // ...\n  }\n  return applicables;\n}\n```\n\n**Call Frequency**:\n- Called once per class transformation\n- Typical application startup: 1000-5000 classes loaded\n- Each OnMethod with regex → pattern compiled 1000-5000 times\n\n#### Performance Impact\n\n**Pattern Compilation Cost**:\n- Simple regex: ~10-50μs\n- Complex regex: ~100-500μs\n- Typical probe: 5-10 regex OnMethods\n- **Per-class cost: 50-5000μs of unnecessary work**\n\n**Aggregate Impact**:\n- 1000 classes × 5 OnMethods × 50μs = **250ms wasted**\n- 5000 classes × 10 OnMethods × 100μs = **5 seconds wasted**\n\n**Memory Churn**:\n- Each Pattern.compile() allocates Pattern object + internal NFA\n- 5000 compilations × 1KB = 5MB temporary allocations\n\n#### Proposed Solution: Pre-compile Patterns\n\n**Step 1: Add Pattern field to OnMethod**\n\n```java\n// In OnMethod.java\npublic class OnMethod {\n  // Existing fields...\n  private volatile Pattern compiledClassPattern = null;\n\n  /**\n   * Returns pre-compiled pattern for class matching.\n   * Pattern is compiled lazily on first access and cached.\n   *\n   * @return compiled pattern, or null if not a regex matcher\n   */\n  public Pattern getClassPattern() {\n    if (!isClassRegexMatcher()) {\n      return null;\n    }\n\n    if (compiledClassPattern == null) {\n      synchronized (this) {\n        if (compiledClassPattern == null) {\n          try {\n            compiledClassPattern = Pattern.compile(getClazz());\n          } catch (PatternSyntaxException e) {\n            log.warn(\"Invalid regex pattern in OnMethod: {}\", getClazz(), e);\n            compiledClassPattern = Pattern.compile(\"(?!)\"); // Never matches\n          }\n        }\n      }\n    }\n    return compiledClassPattern;\n  }\n\n  // Existing methods...\n}\n```\n\n**Step 2: Update BTraceProbeSupport**\n\n```java\nCollection<OnMethod> getApplicableHandlers(BTraceClassReader cr) {\n  Collection<OnMethod> applicables = new ArrayList<>(onMethods.size());\n  String targetName = cr.getJavaClassName();\n\n  outer:\n  for (OnMethod om : onMethods) {\n    String probeClass = om.getClazz();\n    if (probeClass == null || probeClass.isEmpty()) continue;\n\n    if (probeClass.equals(targetName)) {\n      applicables.add(om);\n      continue;\n    }\n\n    // Check regex match - USE PRE-COMPILED PATTERN\n    if (om.isClassRegexMatcher() && !om.isClassAnnotationMatcher()) {\n      Pattern p = om.getClassPattern();  // Pre-compiled, no allocation\n      if (p != null && p.matcher(targetName).matches()) {\n        applicables.add(om);\n        continue;\n      }\n    }\n\n    if (om.isClassAnnotationMatcher()) {\n      Collection<String> annoTypes = cr.getAnnotationTypes();\n      if (om.isClassRegexMatcher()) {\n        Pattern p = om.getClassPattern();  // Pre-compiled, no allocation\n        if (p != null) {\n          for (String annoType : annoTypes) {\n            if (p.matcher(annoType).matches()) {\n              applicables.add(om);\n              continue outer;\n            }\n          }\n        }\n      } else {\n        if (annoTypes.contains(probeClass)) {\n          applicables.add(om);\n          continue;\n        }\n      }\n    }\n\n    // Check subtype hierarchy\n    if (om.isSubtypeMatcher()) {\n      if (isSubTypeOf(cr.getClassName(), cr.getClassLoader(), probeClass)) {\n        applicables.add(om);\n      }\n    }\n  }\n  return applicables;\n}\n```\n\n#### Benefits\n\n**Performance**:\n- Pattern compiled once per OnMethod (lazy initialization)\n- Subsequent calls: O(1) field access\n- **Eliminates 250ms-5s of repeated compilation**\n\n**Memory**:\n- Pattern stored once per OnMethod (not per class transformation)\n- Memory overhead: ~1KB per regex OnMethod (acceptable)\n\n**Thread Safety**:\n- Double-checked locking ensures single compilation\n- `volatile` ensures visibility across threads\n\n#### Alternative: Eager Compilation\n\nCould compile patterns during OnMethod construction instead of lazily:\n\n```java\n// In OnMethod constructor or builder\nif (isClassRegexMatcher()) {\n  try {\n    this.compiledClassPattern = Pattern.compile(clazz);\n  } catch (PatternSyntaxException e) {\n    log.warn(\"Invalid regex pattern: {}\", clazz, e);\n    this.compiledClassPattern = Pattern.compile(\"(?!)\");\n  }\n}\n```\n\n**Tradeoff**:\n- Pros: Simpler code, no locking needed\n- Cons: Wastes work if OnMethod never used for class matching\n- **Recommendation**: Use lazy compilation (minimal complexity, optimal performance)\n\n#### Pattern Already Used Elsewhere\n\nNote: ClassFilter already implements pattern caching correctly:\n\n```java\n// ClassFilter.java:276\nprivate void init(Collection<OnMethod> onMethods) {\n  // ... snip ...\n  for (OnMethod om : onMethods) {\n    String className = om.getClazz();\n    if (om.isClassRegexMatcher()) {\n      if (om.isClassAnnotationMatcher()) {\n        classAnnotationPatterns.add(Pattern.compile(className));  // Compiled once\n      } else {\n        classNamePatterns.add(Pattern.compile(className));  // Compiled once\n      }\n    }\n    // ...\n  }\n}\n```\n\n**Refactoring Opportunity**: Extract pattern caching logic to shared utility.\n\n#### Risk Assessment\n\n- **Fix Complexity**: Medium (4 hours including OnMethod changes and tests)\n- **Testing Effort**: Low (verify patterns compiled once)\n- **Risk**: Low (isolated caching change, no behavior change)\n- **Breaking Changes**: None (internal optimization)\n\n---\n\n### Issue 5: CallGraph Linear Search\n\n**Priority**: P1 (Performance)\n**File**: `btrace-instr/src/main/java/org/openjdk/btrace/instr/CallGraph.java`\n**Type**: Algorithm Inefficiency\n\n#### Problem Description\n\nCallGraph uses O(n) linear search through all nodes for three operations:\n\n**Occurrence 1: addEdge() - Lines 62-69**\n```java\npublic void addEdge(String fromId, String toId) {\n  Node fromNode = null;\n  Node toNode = null;\n  for (Node n : nodes) {  // O(n) search\n    if (n.id.equals(fromId)) {\n      fromNode = n;\n    }\n    if (n.id.equals(toId)) {\n      toNode = n;\n    }\n  }\n  // ... create nodes if needed ...\n  fromNode.addEdge(toNode);\n}\n```\n\n**Occurrence 2: collectOutgoings() - Lines 135-145**\n```java\nprivate void collectOutgoings(String methodId, Set<String> closure) {\n  for (Node n : nodes) {  // O(n) search\n    if (n.id.equals(methodId)) {\n      for (Edge e : n.outgoing) {\n        // ... recursive collection ...\n      }\n      break;\n    }\n  }\n}\n```\n\n**Occurrence 3: collectIncomings() - Lines 149-159**\n```java\nprivate void collectIncomings(String methodId, Set<String> closure) {\n  for (Node n : nodes) {  // O(n) search\n    if (n.id.equals(methodId)) {\n      for (Edge e : n.incoming) {\n        // ... recursive collection ...\n      }\n      break;\n    }\n  }\n}\n```\n\n#### Performance Impact\n\n**Complexity Analysis**:\n- Each lookup: O(n) where n = number of nodes in graph\n- `addEdge()` called for every method call edge (100s-1000s)\n- Total complexity: O(n²) for graph construction\n\n**Real-World Scenarios**:\n- Small probe (10 methods, 20 edges): 10 × 20 = 200 iterations (acceptable)\n- Medium probe (100 methods, 200 edges): 100 × 200 = 20,000 iterations (slow)\n- Large probe (1000 methods, 2000 edges): 1000 × 2000 = 2M iterations (unacceptable)\n\n**Measurement**:\n- Linear search: ~50ns per node comparison\n- 1000-node graph: 1000 × 50ns = 50μs per lookup\n- 2000 edges × 50μs = 100ms total graph construction time\n\n#### Proposed Solution: HashMap Index\n\n```java\npublic final class CallGraph {\n  private final Set<Node> nodes = new HashSet<>();\n  private final Map<String, Node> nodeIndex = new HashMap<>();  // NEW: O(1) lookup index\n  private final Set<Edge> edges = new HashSet<>();\n\n  // ... existing Node and Edge classes ...\n\n  public void addEdge(String fromId, String toId) {\n    // O(1) lookup instead of O(n)\n    Node fromNode = nodeIndex.get(fromId);\n    Node toNode = nodeIndex.get(toId);\n\n    if (fromNode == null) {\n      fromNode = new Node(fromId);\n      nodes.add(fromNode);\n      nodeIndex.put(fromId, fromNode);  // Maintain index\n    }\n    if (toNode == null) {\n      toNode = new Node(toId);\n      nodes.add(toNode);\n      nodeIndex.put(toId, toNode);  // Maintain index\n    }\n\n    fromNode.addEdge(toNode);\n  }\n\n  public void addStarting(String methodId) {\n    // O(1) lookup\n    Node n = nodeIndex.get(methodId);\n    if (n == null) {\n      n = new Node(methodId);\n      nodes.add(n);\n      nodeIndex.put(methodId, n);  // Maintain index\n    }\n    n.entry = true;\n  }\n\n  private void collectOutgoings(String methodId, Set<String> closure) {\n    // O(1) lookup instead of O(n)\n    Node n = nodeIndex.get(methodId);\n    if (n != null) {\n      for (Edge e : n.outgoing) {\n        if (!closure.contains(e.to.id)) {\n          closure.add(e.to.id);\n          collectOutgoings(e.to.id, closure);\n        }\n      }\n    }\n  }\n\n  private void collectIncomings(String methodId, Set<String> closure) {\n    // O(1) lookup instead of O(n)\n    Node n = nodeIndex.get(methodId);\n    if (n != null) {\n      for (Edge e : n.incoming) {\n        if (!closure.contains(e.from.id)) {\n          closure.add(e.from.id);\n          collectIncomings(e.from.id, closure);\n        }\n      }\n    }\n  }\n\n  // hasCycle() - no changes needed (doesn't use lookup)\n\n  // Existing getter methods remain unchanged\n}\n```\n\n#### Benefits\n\n**Performance**:\n- Lookup: O(n) → O(1)\n- Graph construction: O(n²) → O(n)\n- 1000-node graph: 100ms → 2ms (50× speedup)\n\n**Memory**:\n- HashMap overhead: ~32 bytes per entry\n- 1000 nodes: 32KB additional memory\n- Negligible compared to Node objects themselves\n\n**Correctness**:\n- Index maintained in sync with nodes Set\n- No behavior changes (internal optimization only)\n\n#### Testing Strategy\n\n```java\n@Test\nvoid testCallGraphIndexConsistency() {\n  CallGraph graph = new CallGraph();\n\n  // Add edges\n  graph.addEdge(\"method1\", \"method2\");\n  graph.addEdge(\"method2\", \"method3\");\n  graph.addEdge(\"method1\", \"method3\");\n\n  // Verify nodes added correctly\n  assertEquals(3, graph.nodeCount());\n\n  // Verify closure collection works\n  Set<String> closure = graph.getOutgoingClosure(\"method1\");\n  assertTrue(closure.contains(\"method2\"));\n  assertTrue(closure.contains(\"method3\"));\n}\n\n@Test\nvoid testCallGraphPerformance() {\n  CallGraph graph = new CallGraph();\n\n  // Build large graph\n  for (int i = 0; i < 1000; i++) {\n    for (int j = i + 1; j < i + 5 && j < 1000; j++) {\n      graph.addEdge(\"method\" + i, \"method\" + j);\n    }\n  }\n\n  // Verify reasonable construction time (should be < 10ms)\n  long start = System.nanoTime();\n  Set<String> closure = graph.getOutgoingClosure(\"method0\");\n  long duration = System.nanoTime() - start;\n\n  assertTrue(duration < 10_000_000, \"Closure collection too slow: \" + duration + \"ns\");\n}\n```\n\n#### Risk Assessment\n\n- **Fix Complexity**: Low (2 hours)\n- **Testing Effort**: Low (verify index consistency)\n- **Risk**: Low (internal optimization, no API changes)\n- **Breaking Changes**: None\n\n---\n\n### Issue 6: String Transformation Caching\n\n**Priority**: P1 (Performance)\n**File**: `btrace-instr/src/main/java/org/openjdk/btrace/instr/InstrumentUtils.java:253`\n**Type**: Repeated Computation\n\n#### Problem Description\n\nThe `getActionPrefix()` method performs string operations on every call:\n\n```java\n// InstrumentUtils.java:253\nstatic String getActionPrefix(String className) {\n  return Constants.BTRACE_METHOD_PREFIX + className.replace('/', '$') + \"$\";\n}\n```\n\n**Callers**:\n1. `Instrumentor.getActionMethodName()` - called for every OnMethod handler\n2. `BTraceTransformer.unregister()` - called for every OnMethod during unregistration\n\n**Call Frequency**:\n- Typical probe: 10-50 OnMethods\n- Each OnMethod: 1-10 instrumentation points\n- **Total: 10-500 calls per probe with same className**\n\n#### Performance Impact\n\n**Cost per call**:\n- String.replace(): O(n) scan of className\n- String concatenation: 2× StringBuilder allocations\n- Total: ~500ns per call\n\n**Aggregate**:\n- 500 calls × 500ns = 250μs wasted\n- Not huge, but unnecessary\n\n**Memory**:\n- Each call allocates StringBuilder (40 bytes)\n- Each call creates result String (variable size)\n- 500 calls × 40 bytes = 20KB temporary allocations\n\n#### Proposed Solution: Cache in BTraceProbe\n\n```java\n// In BTraceProbe.java (interface)\npublic interface BTraceProbe {\n  // Existing methods...\n\n  /**\n   * Returns the action method prefix for this probe.\n   * This is computed once and cached.\n   *\n   * Format: BTRACE_METHOD_PREFIX + className.replace('/', '$') + \"$\"\n   * Example: \"$btrace$com$example$MyProbe$\"\n   *\n   * @return cached action prefix\n   */\n  default String getActionPrefix() {\n    return Constants.BTRACE_METHOD_PREFIX +\n           getClassName(true).replace('/', '$') + \"$\";\n  }\n}\n```\n\n```java\n// In BTraceProbeSupport.java or BTraceProbePersisted.java\npublic class BTraceProbeSupport implements BTraceProbe {\n  // Existing fields...\n  private String cachedActionPrefix = null;  // NEW: cache field\n\n  @Override\n  public String getActionPrefix() {\n    if (cachedActionPrefix == null) {\n      cachedActionPrefix = Constants.BTRACE_METHOD_PREFIX +\n                          getClassName(true).replace('/', '$') + \"$\";\n    }\n    return cachedActionPrefix;\n  }\n\n  // Existing methods...\n}\n```\n\n```java\n// Update callers to use cached version\n// InstrumentUtils.java - REMOVE getActionPrefix() or mark deprecated\n@Deprecated\nstatic String getActionPrefix(String className) {\n  // Kept for compatibility, but users should use BTraceProbe.getActionPrefix()\n  return Constants.BTRACE_METHOD_PREFIX + className.replace('/', '$') + \"$\";\n}\n\nstatic String getActionMethodName(BTraceProbe bp, String name) {\n  return bp.getActionPrefix() + name;  // Use cached version\n}\n```\n\n#### Alternative: Static Cache\n\nIf probe doesn't have convenient place for field:\n\n```java\n// InstrumentUtils.java\nprivate static final Map<String, String> actionPrefixCache = new ConcurrentHashMap<>();\n\nstatic String getActionPrefix(String className) {\n  return actionPrefixCache.computeIfAbsent(className, cn ->\n    Constants.BTRACE_METHOD_PREFIX + cn.replace('/', '$') + \"$\"\n  );\n}\n```\n\n**Tradeoff**:\n- Pros: No changes to BTraceProbe interface\n- Cons: Global cache grows indefinitely (classloader leak risk)\n- **Recommendation**: Use per-probe caching (better lifecycle management)\n\n#### Benefits\n\n**Performance**:\n- First call: Same cost as before\n- Subsequent calls: Field access (~2ns vs ~500ns)\n- **250× speedup for repeated calls**\n\n**Memory**:\n- One String per probe (~50 bytes)\n- Eliminates 20KB temporary allocations per probe\n\n#### Risk Assessment\n\n- **Fix Complexity**: Low (1 hour)\n- **Testing Effort**: Minimal (verify same output)\n- **Risk**: Minimal (pure refactoring, no behavior change)\n- **Breaking Changes**: None (internal optimization)\n\n---\n\n### Issue 7: Test Infrastructure O(n²) Allocation\n\n**Priority**: P1 (Test Performance)\n**File**: `btrace-instr/src/test/java/org/openjdk/btrace/instr/InstrumentorTestBase.java:406-418`\n**Type**: Algorithm Inefficiency\n\n#### Problem Description\n\nThe `loadFile()` method uses quadratic memory allocation:\n\n```java\nprivate byte[] loadFile(InputStream is) throws IOException {\n  byte[] result = new byte[0];  // Start with empty array\n  byte[] buffer = new byte[1024];\n  int read = -1;\n\n  while ((read = is.read(buffer)) > 0) {\n    // Allocate new array with old data + new data\n    byte[] newresult = new byte[result.length + read];  // O(n²) allocation\n\n    // Copy old data\n    System.arraycopy(result, 0, newresult, 0, result.length);\n\n    // Copy new data\n    System.arraycopy(buffer, 0, newresult, result.length, read);\n\n    result = newresult;  // Old array becomes garbage\n  }\n  return result;\n}\n```\n\n#### Performance Impact\n\n**For 10KB file with 1KB buffer (10 iterations)**:\n- Iteration 1: allocate 1KB, copy 1KB\n- Iteration 2: allocate 2KB, copy 2KB (1KB old + 1KB new)\n- Iteration 3: allocate 3KB, copy 3KB (2KB old + 1KB new)\n- ...\n- Iteration 10: allocate 10KB, copy 10KB (9KB old + 1KB new)\n\n**Total**:\n- Allocations: 1+2+3+...+10 = 55KB (should be 10KB)\n- Copies: 1+2+3+...+10 = 55KB copied (should be 10KB)\n- **5.5× memory overhead**\n\n**For larger files**:\n- 100KB file: 5050KB allocated (50× overhead)\n- 1MB file: 500MB allocated (500× overhead)\n\n**Test Impact**:\n- Typical golden file: 5-10KB (acceptable overhead)\n- Large golden file (AllLines.golden): 35KB (650KB overhead)\n- Multiplied by 396 golden files = wasted GC pressure during tests\n\n#### Proposed Solution: Use ByteArrayOutputStream\n\n```java\nprivate byte[] loadFile(InputStream is) throws IOException {\n  // ByteArrayOutputStream uses geometric growth (2× on resize)\n  ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);\n  byte[] buffer = new byte[8192];\n  int read;\n\n  while ((read = is.read(buffer)) != -1) {\n    baos.write(buffer, 0, read);  // Appends to internal buffer\n  }\n\n  return baos.toByteArray();  // Single final copy\n}\n```\n\n**How ByteArrayOutputStream Works**:\n- Initial buffer: 8192 bytes\n- When full: double size (8KB → 16KB → 32KB → ...)\n- Growth factor: 2× (geometric, not linear)\n- Only resizes when necessary\n\n**For 10KB file**:\n- Allocations: 8KB + 16KB = 24KB total (vs 55KB)\n- Copies: 8KB copied once during resize (vs 55KB)\n- **2.4× memory usage (vs 5.5×)**\n\n#### Benefits\n\n**Performance**:\n- O(n²) → O(n log n) allocation complexity\n- O(n²) → O(n) copy operations\n- 10KB file: 55KB → 24KB allocations (2.3× reduction)\n- 1MB file: 500MB → 2MB allocations (250× reduction)\n\n**Code Simplicity**:\n- 12 lines → 6 lines\n- Standard library class (well-tested)\n- More readable\n\n#### Alternative Solutions\n\n**Option A: Pre-allocated buffer** (if file size known):\n```java\nprivate byte[] loadFile(InputStream is, int expectedSize) throws IOException {\n  ByteArrayOutputStream baos = new ByteArrayOutputStream(expectedSize);\n  // ... rest same ...\n}\n```\n\n**Option B: Files.readAllBytes()** (if InputStream is FileInputStream):\n```java\nprivate byte[] loadFile(String path) throws IOException {\n  return Files.readAllBytes(Paths.get(path));\n}\n```\n\n**Recommendation**: Use ByteArrayOutputStream (simple, works for all InputStreams)\n\n#### Risk Assessment\n\n- **Fix Complexity**: Trivial (30 minutes)\n- **Testing Effort**: None (existing tests verify correctness)\n- **Risk**: None (standard library, isolated utility)\n- **Breaking Changes**: None\n\n---\n\n## Part 3: Allocation Pressure Reduction (P2)\n\n### Issue 8: InstrumentingMethodVisitor Hot Path Allocations\n\n**Priority**: P2 (Optimization)\n**File**: `btrace-instr/src/main/java/org/openjdk/btrace/instr/InstrumentingMethodVisitor.java`\n**Type**: Hot Path Allocation\n\n#### Problem Description\n\nSavedState objects are allocated on every jump/branch/try-catch in instrumented methods:\n\n```java\n// Line 234 - visitJumpInsn\nSavedState state = new SavedState(localTypes, stack, newLocals, SavedState.CONDITIONAL);\njumpTargetStates.put(label, state);\n\n// Line 246 - visitTableSwitchInsn\nfor (Label l : labels) {\n  SavedState state = new SavedState(localTypes, stack, newLocals, SavedState.CONDITIONAL);\n  jumpTargetStates.put(l, state);\n}\n\n// Line 342 - visitTryCatchBlock\nSavedState state = new SavedState(localTypes, stack, newLocals, SavedState.TRY_CATCH);\njumpTargetStates.put(handler, state);\n```\n\n**SavedState Constructor** (lines 1670-1679):\n```java\nSavedState(LocalVarTypes lvTypes, SimulatedStack sStack,\n           Collection<LocalVarSlot> newLocals, int kind) {\n  this.lvTypes = lvTypes.toArray();        // NEW ALLOCATION (Object[] copy)\n  this.sStack = sStack.toArray();          // NEW ALLOCATION (Object[] copy)\n  this.newLocals = new HashSet<>(newLocals);  // NEW ALLOCATION (HashSet copy)\n  this.kind = kind;\n}\n```\n\n#### Impact Analysis\n\n**Allocation Profile** (per SavedState):\n- LocalVarTypes.toArray(): 10-50 Object[] elements (80-400 bytes)\n- SimulatedStack.toArray(): 0-20 Object[] elements (0-160 bytes)\n- HashSet copy: 0-5 elements (100-200 bytes)\n- **Total: ~200-800 bytes per SavedState**\n\n**Frequency**:\n- Typical method: 5-20 jumps/branches\n- Complex method: 50-100 jumps/branches\n- Switch statement: 10-100 cases\n- **Per method: 10-200 SavedState allocations**\n\n**Aggregate**:\n- Simple probe (10 methods): 100-500 SavedState objects\n- Complex probe (100 methods): 1000-5000 SavedState objects\n- Memory: 200KB-4MB temporary allocations per probe instrumentation\n\n#### Proposed Solutions\n\n**Option A: Lazy Copy-on-Read (Recommended)**\n\nDon't copy data until it's actually needed (often never accessed):\n\n```java\nclass SavedState {\n  // Store references instead of copies\n  private final LocalVarTypes lvTypesRef;\n  private final SimulatedStack sStackRef;\n  private final Collection<LocalVarSlot> newLocalsRef;\n\n  // Lazy materialized copies\n  private Object[] lvTypesCopy = null;\n  private Object[] sStackCopy = null;\n  private Set<LocalVarSlot> newLocalsCopy = null;\n\n  private final int kind;\n\n  SavedState(LocalVarTypes lvTypes, SimulatedStack sStack,\n             Collection<LocalVarSlot> newLocals, int kind) {\n    this.lvTypesRef = lvTypes;\n    this.sStackRef = sStack;\n    this.newLocalsRef = newLocals;\n    this.kind = kind;\n  }\n\n  Object[] getLvTypes() {\n    if (lvTypesCopy == null) {\n      lvTypesCopy = lvTypesRef.toArray();  // Lazy copy\n    }\n    return lvTypesCopy;\n  }\n\n  Object[] getSStack() {\n    if (sStackCopy == null) {\n      sStackCopy = sStackRef.toArray();  // Lazy copy\n    }\n    return sStackCopy;\n  }\n\n  Set<LocalVarSlot> getNewLocals() {\n    if (newLocalsCopy == null) {\n      newLocalsCopy = new HashSet<>(newLocalsRef);  // Lazy copy\n    }\n    return newLocalsCopy;\n  }\n\n  int getKind() {\n    return kind;\n  }\n}\n```\n\n**Benefits**:\n- Zero allocation if state never read (common for unconditional jumps)\n- Deferred allocation to when actually needed\n- Simpler than pooling (no lifecycle management)\n\n**Tradeoffs**:\n- Potential correctness issue: references could be mutated\n- Mitigation: Ensure referenced objects are immutable or not mutated after SavedState creation\n- Analysis needed: verify LocalVarTypes/SimulatedStack not mutated after snapshot\n\n**Option B: ThreadLocal Object Pool**\n\nReuse SavedState objects across multiple method instrumentations:\n\n```java\nstatic class SavedStatePool {\n  private static final ThreadLocal<ArrayDeque<SavedState>> pool =\n    ThreadLocal.withInitial(() -> new ArrayDeque<>(16));\n\n  static SavedState acquire(LocalVarTypes lvTypes, SimulatedStack sStack,\n                           Collection<LocalVarSlot> newLocals, int kind) {\n    SavedState state = pool.get().poll();\n    if (state == null) {\n      state = new SavedState();  // Allocate if pool empty\n    }\n    state.init(lvTypes, sStack, newLocals, kind);  // Reuse existing object\n    return state;\n  }\n\n  static void release(SavedState state) {\n    state.clear();  // Reset for reuse\n    pool.get().offer(state);\n  }\n}\n\nclass SavedState {\n  private Object[] lvTypes;\n  private Object[] sStack;\n  private Set<LocalVarSlot> newLocals;\n  private int kind;\n\n  SavedState() {\n    // Empty constructor for pooling\n  }\n\n  void init(LocalVarTypes lvTypes, SimulatedStack sStack,\n            Collection<LocalVarSlot> newLocals, int kind) {\n    this.lvTypes = lvTypes.toArray();\n    this.sStack = sStack.toArray();\n    this.newLocals = new HashSet<>(newLocals);\n    this.kind = kind;\n  }\n\n  void clear() {\n    this.lvTypes = null;\n    this.sStack = null;\n    this.newLocals = null;\n  }\n\n  // Getters remain same...\n}\n```\n\n**Challenges**:\n- SavedState stored in HashMap (needs careful lifecycle tracking)\n- Must call release() after HashMap.remove()\n- Risk of leaks if release() missed\n- More complex than Option A\n\n**Benefits**:\n- Eliminates SavedState object allocations (reuses objects)\n- Still copies arrays (can't avoid without deeper changes)\n- ThreadLocal avoids synchronization\n\n#### Recommendation\n\n**Start with Option A (Lazy Copy-on-Read)**:\n1. Simpler implementation\n2. Lower risk (no lifecycle management)\n3. Significant benefit (many states never read)\n4. Can profile to determine if Option B needed\n\n**If profiling shows high read rate**:\n- Consider Option B (pooling)\n- Or hybrid: lazy copy + pooling\n\n#### Implementation Plan\n\n1. Refactor SavedState to lazy copy-on-read\n2. Audit LocalVarTypes/SimulatedStack for mutation after snapshot\n3. Add defensive copies if mutation found\n4. Test with complex methods (many branches)\n5. Profile allocation reduction\n\n#### Risk Assessment\n\n- **Fix Complexity**: Medium (4 hours for Option A, 8 hours for Option B)\n- **Testing Effort**: Medium (verify correctness, profile allocation)\n- **Risk**: Medium (touches hot path, requires careful testing)\n- **Breaking Changes**: None (internal implementation)\n\n---\n\n### Issue 9: VariableMapper Array Resizing\n\n**Priority**: P2 (Optimization)\n**File**: `btrace-instr/src/main/java/org/openjdk/btrace/instr/VariableMapper.java`\n**Type**: Frequent Allocation\n\n#### Problem Description\n\nVariableMapper performs frequent array copies during method transformation:\n\n**Arrays.copyOf() Calls**:\n\n1. **Line 54 - noteLabel()**: Called on every label in method\n```java\npublic void noteLabel(Label label) {\n  labelMappings.put(currentLabel, Arrays.copyOf(mapping, nextMappedVar));\n  currentLabel = label;\n}\n```\n\n2. **Line 63 - setMapping()**: Called when mapping array needs growth\n```java\nvoid setMapping(int from, int to, int size) {\n  int padding = size == 1 ? 0 : 1;\n  if (mapping.length <= from + padding) {\n    mapping = Arrays.copyOf(mapping, Math.max(mapping.length * 2, from + padding + 1));\n  }\n  // ...\n}\n```\n\n3. **Line 83 - remap()**: Called when mapping array needs growth\n```java\npublic int remap(int var, int size) {\n  // ...\n  int offset = var - argsSize;\n  if (offset >= mapping.length) {\n    mapping = Arrays.copyOf(mapping, Math.max(mapping.length * 2, offset + 1));\n  }\n  // ...\n}\n```\n\n#### Impact Analysis\n\n**Frequency**:\n- Typical method: 10-30 labels → 10-30 label mapping copies\n- Each label copy: Arrays.copyOf(mapping, nextMappedVar)\n- Array growth: 5-10 times per method (when adding new variables)\n\n**Cost Per Copy**:\n- Small method (8 locals): copy 8 ints = 32 bytes\n- Medium method (32 locals): copy 32 ints = 128 bytes\n- Large method (128 locals): copy 128 ints = 512 bytes\n\n**Aggregate**:\n- 20 labels × 128 bytes = 2.5KB copies per method\n- 100 methods × 2.5KB = 250KB temporary allocations per probe\n\n#### Proposed Solutions\n\n**Option A: Track Used Length (Recommended)**\n\nDon't copy entire mapping array, only used portion:\n\n```java\npublic class VariableMapper {\n  private final int argsSize;\n  private int nextMappedVar = 0;\n  private int[] mapping = new int[64];  // Larger initial size (was 8)\n\n  private static final Label FIRST_LABEL = new Label();\n  private Label currentLabel = FIRST_LABEL;\n  private final Map<Label, int[]> labelMappings = new HashMap<>(16);\n\n  public VariableMapper(int argsSize) {\n    this.argsSize = argsSize;\n    nextMappedVar = argsSize;\n  }\n\n  public void noteLabel(Label label) {\n    // Copy only used portion (not entire array)\n    labelMappings.put(currentLabel, Arrays.copyOf(mapping, nextMappedVar));\n    currentLabel = label;\n  }\n\n  // Rest remains same...\n}\n```\n\n**Benefits**:\n- Reduces copy size from mapping.length to nextMappedVar\n- Typical: 64 ints → 10 ints copied (6× reduction)\n- Larger initial size reduces growth events\n\n**Option B: Cache Identical Mappings**\n\nConsecutive labels often have identical mappings (linear code):\n\n```java\npublic void noteLabel(Label label) {\n  int[] prevMapping = labelMappings.get(currentLabel);\n\n  // Check if current mapping same as previous\n  if (prevMapping != null && Arrays.equals(prevMapping, 0, nextMappedVar,\n                                            mapping, 0, nextMappedVar)) {\n    labelMappings.put(label, prevMapping);  // Reuse (no copy)\n  } else {\n    labelMappings.put(label, Arrays.copyOf(mapping, nextMappedVar));  // Copy needed\n  }\n\n  currentLabel = label;\n}\n```\n\n**Benefits**:\n- Eliminates copies for consecutive labels with same mapping\n- Common in linear code (50-80% of labels)\n- Shares array instances (reduces memory)\n\n**Tradeoffs**:\n- Arrays.equals() cost: O(n) comparison\n- Only beneficial if >50% labels are identical\n- More complex logic\n\n**Option C: Hybrid (Recommended)**\n\nCombine Option A (track used length) + larger initial size:\n\n```java\nprivate int[] mapping = new int[64];  // Increased from 8\n\npublic void noteLabel(Label label) {\n  labelMappings.put(currentLabel, Arrays.copyOf(mapping, nextMappedVar));\n  currentLabel = label;\n}\n```\n\nSimple change with good results:\n- Larger initial size reduces growth events\n- Copy only used portion reduces copy size\n- No complex caching logic\n\n#### Additional Optimization: Pre-size from Method Signature\n\nCan estimate variable count from method descriptor:\n\n```java\npublic VariableMapper(int argsSize, String methodDescriptor) {\n  this.argsSize = argsSize;\n  this.nextMappedVar = argsSize;\n\n  // Estimate: args + 8 locals + 16 instrumentation vars\n  int estimatedVars = argsSize + 8 + 16;\n  this.mapping = new int[Math.max(64, estimatedVars)];\n}\n```\n\nAvoids most resize operations.\n\n#### Implementation Recommendation\n\n**Phase 1** (Low effort, good benefit):\n- Increase initial size to 64\n- Copy only nextMappedVar portion\n\n**Phase 2** (If profiling shows benefit):\n- Add mapping caching (Option B)\n- Add method descriptor pre-sizing\n\n#### Risk Assessment\n\n- **Fix Complexity**: Low (3 hours for Phase 1)\n- **Testing Effort**: Low (verify same behavior)\n- **Risk**: Low (internal optimization)\n- **Breaking Changes**: None\n\n---\n\n## Part 4: Code Quality Issues (P3)\n\n### Issue 10: Debug Code in Production\n\n**Priority**: P3 (Code Quality)\n**File**: `btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodInstrumentor.java:511`\n**Type**: Debug Code\n\n#### Problem\n\nValidationResult constructor contains debug stack trace dump:\n\n```java\npublic ValidationResult(boolean valid, int[] argsIndex) {\n  if (argsIndex == null) {\n    Thread.dumpStack();  // DEBUG CODE - PRINTS TO STDERR\n  }\n  isValid = valid;\n  this.argsIndex = argsIndex;\n}\n```\n\n#### Impact\n\n- Stack traces printed to stderr in production\n- No logging context or filtering\n- Confusing for users (looks like error)\n- Indicates incomplete error handling\n\n#### Solution\n\nReplace with proper null check:\n\n```java\npublic ValidationResult(boolean valid, int[] argsIndex) {\n  this.argsIndex = Objects.requireNonNull(argsIndex, \"argsIndex must not be null\");\n  this.isValid = valid;\n}\n```\n\n#### Risk Assessment\n\n- **Fix Complexity**: Trivial (15 minutes)\n- **Risk**: None\n- **Breaking Changes**: None (fixes broken behavior)\n\n---\n\n### Issue 11: Raw Types in Test Code\n\n**Priority**: P3 (Type Safety)\n**Files**: Multiple test files\n**Type**: Type Safety Violation\n\n#### Examples Found\n\n1. `test/btrace/BTRACE87.java:15`:\n```java\nList a = new ArrayList();  // Raw type\n```\n\n2. `test/DerivedClass.java:53`:\n```java\nsuper(new ArrayList());  // Raw type\n```\n\n#### Solution\n\nAdd proper generics:\n\n```java\nList<Object> a = new ArrayList<>();\nsuper(new ArrayList<Object>());\n```\n\n#### Survey Needed\n\nFull audit of test code to find all raw type violations.\n\n#### Risk Assessment\n\n- **Fix Complexity**: Medium (2 hours after survey)\n- **Risk**: Low (test-only changes)\n- **Breaking Changes**: None\n\n---\n\n### Issue 12: Test Duplication\n\n**Priority**: P3 (Maintenance)\n**Location**: Test infrastructure\n**Type**: Test Organization\n\n#### Problem\n\n396 golden files for 199 test scripts (2× duplication):\n- `onmethod/` directory structure paralleled in multiple locations\n- Each test generates 2 golden files\n\n#### Investigation Needed\n\n1. Why 2 files per script?\n2. Different dispatch modes (INVOKESTATIC vs INVOKEDYNAMIC)?\n3. Different Java versions?\n4. Can files be generated from single source?\n\n#### Risk Assessment\n\n- **Fix Complexity**: High (8 hours investigation + fix)\n- **Risk**: Medium (test infrastructure changes)\n\n---\n\n## Part 5: Missing Test Coverage (P4)\n\n### Issue 13: Edge Case Testing Gaps\n\n**Priority**: P4 (Risk Mitigation)\n**Type**: Test Coverage\n\n#### Missing Coverage Areas\n\n1. **Concurrency**: Multi-threaded class transformation\n2. **ClassLoader GC**: Probe cleanup with dead classloaders\n3. **Large Classes**: Methods with >256 locals, >65KB bytecode\n4. **Cache Invalidation**: Handler cache consistency\n\n#### Proposed Tests\n\n**Concurrency Test**:\n```java\n@Test\nvoid testConcurrentTransformation() {\n  BTraceTransformer transformer = new BTraceTransformer();\n  BTraceProbe probe = createTestProbe();\n  transformer.register(probe);\n\n  // 10 threads transforming same class\n  CountDownLatch latch = new CountDownLatch(10);\n  ExecutorService executor = Executors.newFixedThreadPool(10);\n\n  for (int i = 0; i < 10; i++) {\n    executor.submit(() -> {\n      try {\n        byte[] classBytes = loadClass(\"TestTarget\");\n        byte[] result = transformer.transform(null, \"TestTarget\",\n                                             null, null, classBytes);\n        assertNotNull(result);\n      } finally {\n        latch.countDown();\n      }\n    });\n  }\n\n  assertTrue(latch.await(10, TimeUnit.SECONDS));\n}\n```\n\n**ClassLoader GC Test**:\n```java\n@Test\nvoid testClassLoaderGC() {\n  WeakReference<ClassLoader> clRef = new WeakReference<>(\n    new URLClassLoader(new URL[0])\n  );\n\n  // Register probe with classloader\n  BTraceProbe probe = createProbeWithClassLoader(clRef.get());\n  HandlerRepositoryImpl.registerProbe(probe);\n\n  // Force GC\n  System.gc();\n  Thread.sleep(100);\n  System.gc();\n\n  // Verify classloader collected\n  assertNull(clRef.get(), \"ClassLoader not garbage collected\");\n\n  // Verify no memory leak in ClassCache\n  // (Requires access to ClassCache internals)\n}\n```\n\n**Large Method Test**:\n```java\n@Test\nvoid testLargeMethod() {\n  // Generate class with 300 local variables\n  ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);\n  cw.visit(V1_8, ACC_PUBLIC, \"LargeMethod\", null, \"java/lang/Object\", null);\n\n  MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, \"test\", \"()V\", null, null);\n  mv.visitCode();\n\n  // Create 300 local variables\n  for (int i = 0; i < 300; i++) {\n    mv.visitLdcInsn(i);\n    mv.visitVarInsn(ISTORE, i + 1);\n  }\n\n  mv.visitInsn(RETURN);\n  mv.visitMaxs(0, 0);\n  mv.visitEnd();\n  cw.visitEnd();\n\n  // Transform with BTrace\n  byte[] classBytes = cw.toByteArray();\n  BTraceTransformer transformer = new BTraceTransformer();\n  transformer.register(createTestProbe());\n\n  byte[] result = transformer.transform(null, \"LargeMethod\",\n                                       null, null, classBytes);\n\n  assertNotNull(result, \"Failed to instrument large method\");\n\n  // Verify instrumented class loads and runs\n  ClassLoader cl = new ByteArrayClassLoader(result);\n  Class<?> clazz = cl.loadClass(\"LargeMethod\");\n  clazz.getMethod(\"test\").invoke(clazz.newInstance());\n}\n```\n\n**Handler Cache Test**:\n```java\n@Test\nvoid testHandlerCacheInvalidation() {\n  BTraceProbe probe = createTestProbe(\"TestProbe\");\n  HandlerRepositoryImpl.registerProbe(probe);\n\n  // Get handler (should cache)\n  byte[] handler1 = HandlerRepositoryImpl.getProbeHandler(\n    \"com.example.Test\", \"TestProbe\", \"onMethod\", \"()V\");\n\n  // Get again (should hit cache)\n  byte[] handler2 = HandlerRepositoryImpl.getProbeHandler(\n    \"com.example.Test\", \"TestProbe\", \"onMethod\", \"()V\");\n\n  assertSame(handler1, handler2, \"Should return cached bytecode\");\n\n  // Unregister probe\n  HandlerRepositoryImpl.unregisterProbe(probe);\n\n  // Re-register\n  HandlerRepositoryImpl.registerProbe(probe);\n\n  // Get handler again (cache should be invalidated)\n  byte[] handler3 = HandlerRepositoryImpl.getProbeHandler(\n    \"com.example.Test\", \"TestProbe\", \"onMethod\", \"()V\");\n\n  assertNotSame(handler1, handler3, \"Cache should be invalidated\");\n}\n```\n\n#### Risk Assessment\n\n- **Fix Complexity**: High (16 hours total)\n- **Risk**: Low (additive testing)\n- **Value**: Medium (catches edge case bugs)\n\n---\n\n## Implementation Roadmap\n\n### Sprint 1: Critical Fixes (1 day)\n**Focus**: Correctness bugs that could cause silent failures\n\n1. Fix MethodTracker copy bug (30 min)\n   - File: `MethodTracker.java:62`\n   - Change 1 line\n   - Add unit test\n\n2. Remove Thread.dumpStack() (15 min)\n   - File: `MethodInstrumentor.java:511`\n   - Replace with Objects.requireNonNull()\n\n3. Replace magic 0xFFFFFFFF (4 hours)\n   - File: `VariableMapper.java:136,139`\n   - Add exception-based error handling\n   - Update call sites\n   - Add error path tests\n\n4. Fix test loadFile() O(n²) (30 min)\n   - File: `InstrumentorTestBase.java:406-418`\n   - Replace with ByteArrayOutputStream\n   - Verify tests pass\n\n**Outcome**: All P0 issues resolved\n\n---\n\n### Sprint 2: Performance Wins (2 days)\n**Focus**: High-impact optimizations\n\n5. Cache handler bytecode (3 hours)\n   - File: `HandlerRepositoryImpl.java:43-77`\n   - Add ConcurrentHashMap cache\n   - Implement cache invalidation\n   - Add cache hit/miss tests\n\n6. Cache compiled patterns (4 hours)\n   - File: `OnMethod.java` (new field)\n   - File: `BTraceProbeSupport.java:103,112` (use cached)\n   - Lazy pattern compilation\n   - Pattern error handling\n\n7. Add CallGraph HashMap index (2 hours)\n   - File: `CallGraph.java`\n   - Add Map<String, Node> index\n   - Update addEdge/addStarting/collect methods\n   - Verify hasCycle() still works\n\n8. Cache getActionPrefix (1 hour)\n   - File: `BTraceProbe.java` (new method)\n   - File: `BTraceProbeSupport.java` (cache field)\n   - Update callers\n\n**Outcome**: 20-30% transformation speedup\n\n---\n\n### Sprint 3: Allocation Reduction (1 day)\n**Focus**: Reduce GC pressure\n\n9. InstrumentingMethodVisitor lazy copy (4 hours)\n   - File: `InstrumentingMethodVisitor.java:1670-1679`\n   - Refactor SavedState to lazy copy-on-read\n   - Audit for mutation after snapshot\n   - Profile allocation reduction\n\n10. VariableMapper pre-sizing (3 hours)\n    - File: `VariableMapper.java:19,54`\n    - Increase initial size to 64\n    - Copy only nextMappedVar portion\n    - Test with large methods\n\n**Outcome**: 40-60% allocation reduction\n\n---\n\n### Sprint 4: Code Quality (2 days)\n**Focus**: Maintainability\n\n11. Fix raw types in tests (2 hours)\n    - Survey all test files\n    - Add proper generics\n    - Verify tests pass\n\n12. Investigate test duplication (8 hours)\n    - Analyze why 2 golden files per script\n    - Design consolidation strategy\n    - Implement if beneficial\n\n**Outcome**: Improved type safety and test maintainability\n\n---\n\n### Sprint 5: Testing (2 days)\n**Focus**: Edge case coverage\n\n13. Add edge case tests (16 hours)\n    - Concurrency test (4 hours)\n    - ClassLoader GC test (4 hours)\n    - Large method test (4 hours)\n    - Handler cache test (4 hours)\n\n**Outcome**: >85% hot path coverage\n\n---\n\n## Success Metrics\n\n### Performance Targets\n\n| Metric | Baseline | Target | Measurement |\n|--------|----------|--------|-------------|\n| Transformation Speed | 100% | 70-80% | Microbenchmark: 1000 classes |\n| Memory Allocations | 100% | 40-60% | Allocation profiler |\n| Handler Lookup | ~1ms | ~100ns | Cached invokedynamic linkage |\n| Pattern Matching | 10-100μs | <1μs | Cached pattern per class |\n\n### Quality Targets\n\n| Metric | Baseline | Target |\n|--------|----------|--------|\n| Magic Values | 1 (0xFFFFFFFF) | 0 |\n| Debug Code | 1 (Thread.dumpStack) | 0 |\n| Raw Types | 2+ | 0 |\n| Test Coverage | ~70% | >85% |\n| Data Corruption Bugs | 1 (MethodTracker) | 0 |\n\n---\n\n## Risk Assessment\n\n### Low Risk (Ship Independently)\n- MethodTracker bug fix ✓\n- Thread.dumpStack removal ✓\n- Test loadFile() fix ✓\n- CallGraph indexing ✓\n- Pattern caching ✓\n- Handler bytecode caching ✓\n- String caching ✓\n\n### Medium Risk (Extra Testing Needed)\n- Magic value removal (changes error contracts)\n- SavedState lazy copy (requires mutation audit)\n- VariableMapper resizing (off-by-one potential)\n\n### High Risk (Profile First)\n- Test duplication removal (may break compatibility)\n\n---\n\n## Critical Files Reference\n\n### Must Review for Implementation\n\n| File | Issues | Priority | Effort |\n|------|--------|----------|--------|\n| `MethodTracker.java:62` | Copy-paste bug | P0 | 30m |\n| `VariableMapper.java:136,139` | Magic values | P0 | 4h |\n| `HandlerRepositoryImpl.java:43-77` | Handler caching | P1 | 3h |\n| `BTraceProbeSupport.java:103,112` | Pattern compilation | P1 | 4h |\n| `CallGraph.java:62-69,135-145,149-159` | Linear search | P1 | 2h |\n| `InstrumentUtils.java:253` | String transformations | P1 | 1h |\n| `InstrumentorTestBase.java:406-418` | O(n²) file loading | P1 | 30m |\n| `InstrumentingMethodVisitor.java:1670-1679` | SavedState allocations | P2 | 4h |\n| `MethodInstrumentor.java:511` | Debug code | P3 | 15m |\n\n---\n\n## Conclusion\n\nThe btrace-instr module is generally well-architected but suffers from:\n\n1. **One critical correctness bug** (MethodTracker data corruption)\n2. **Multiple hot-path performance issues** (handler regeneration, pattern compilation)\n3. **Excessive allocations** (SavedState, VariableMapper, test infrastructure)\n\n### Recommended Immediate Actions\n\n**Fix P0+P1 issues first** (estimated 3 days):\n- Eliminates data corruption bug\n- Provides 20-30% performance improvement\n- Reduces memory pressure by 40-60%\n- Low risk, high value\n\n### Long-term Strategy\n\nAddress P2-P4 issues incrementally:\n- Profile allocation patterns to verify optimization value\n- Expand test coverage for edge cases\n- Improve code quality (remove magic values, raw types)\n- Consider architectural refactoring for test infrastructure\n\n### Key Insight\n\nMost issues are **optimization opportunities** rather than fundamental design flaws. The instrumentation engine architecture is sound; it just needs tuning for production performance characteristics.\n\n---\n\n**End of Document**\n"
  },
  {
    "path": "docs/architecture/ExtensionConfiguration.md",
    "content": "# BTrace Extension Configuration\n\n## Overview\n\nExtension configuration allows users to customize extension loading behavior, enable/disable specific extensions, and pass extension-specific settings.\n\n## Configuration File Locations\n\nConfiguration files are searched in priority order (highest to lowest):\n\n1. **Command-line override**: `-Dbtrace.extensions.config=/path/to/config`\n2. **User config**: `~/.btrace/extensions.conf`\n3. **System config**: `$BTRACE_HOME/conf/extensions.conf`\n\nThe first file found is used. Settings from multiple files are NOT merged.\n\n## Configuration Format\n\nUses standard Java properties format:\n\n```properties\n# Extension Control\n# Comma-separated list of extension IDs to enable (empty = all enabled)\nextensions.enabled=\n\n# Comma-separated list of extension IDs to disable\nextensions.disabled=\n\n# Auto-load extensions on demand (default: true)\nextensions.autoload=true\n\n# Extension-specific settings (passed to extension on load)\n# Format: <extension-id>.<setting-name>=<value>\nbtrace-metrics.histogram.default-precision=3\nbtrace-metrics.stats.window-size=1000\n```\n\n## Configuration Properties\n\n### Global Settings\n\n**extensions.enabled**\n- Format: comma-separated extension IDs\n- Default: (empty - all enabled)\n- Example: `extensions.enabled=btrace-metrics,btrace-custom`\n- Description: Whitelist of extensions to load. If set, only listed extensions are loaded. If empty or not set, all discovered extensions are enabled (unless explicitly disabled).\n\n**extensions.disabled**\n- Format: comma-separated extension IDs\n- Default: (empty - none disabled)\n- Example: `extensions.disabled=btrace-old-metrics`\n- Description: Blacklist of extensions to prevent from loading. Takes precedence over `extensions.enabled`.\n\n**extensions.autoload**\n- Format: boolean (true/false)\n- Default: `true`\n- Description: If `true`, extensions are loaded on demand when scripts use their services. If `false`, all enabled extensions are loaded at agent startup.\n\n### Extension-Specific Settings\n\nExtensions can define custom configuration properties using the pattern:\n```\n<extension-id>.<setting-name>=<value>\n```\n\nExamples:\n```properties\n# BTrace Metrics settings\nbtrace-metrics.histogram.default-precision=3\nbtrace-metrics.histogram.max-value=3600000000\nbtrace-metrics.stats.window-size=1000\n\n# Custom extension settings\nmy-extension.feature.enabled=true\nmy-extension.endpoint=http://localhost:8080\n```\n\nExtension-specific settings are passed to the extension when loaded. Extensions can access these via their configuration API.\n\n## Usage Examples\n\n### Example 1: Disable Specific Extension\n\n```properties\n# Disable legacy metrics extension\nextensions.disabled=btrace-old-metrics\n```\n\n### Example 2: Whitelist Extensions\n\n```properties\n# Only load metrics and custom extensions\nextensions.enabled=btrace-metrics,my-custom-extension\n```\n\n### Example 3: Configure Extension Settings\n\n```properties\n# Configure metrics extension\nbtrace-metrics.histogram.default-precision=3\nbtrace-metrics.histogram.max-value=3600000000\n```\n\n### Example 4: Load All Extensions at Startup\n\n```properties\n# Disable lazy loading, load all extensions immediately\nextensions.autoload=false\n```\n\n## API Integration\n\n### ExtensionConfig Class\n\nNew class to manage extension configuration:\n\n```java\npublic class ExtensionConfig {\n  public boolean isEnabled(String extensionId);\n  public boolean isAutoLoad();\n  public Properties getExtensionProperties(String extensionId);\n}\n```\n\n### ExtensionLoader Integration\n\nExtensionLoader will:\n1. Load configuration on initialization\n2. Filter discovered extensions based on enabled/disabled lists\n3. Apply autoload setting (lazy vs eager loading)\n4. Pass extension-specific properties when loading extensions\n\n### Configuration Loading Priority\n\n```\nCommand-line (-Dbtrace.extensions.config)\n    ↓\nUser config (~/.btrace/extensions.conf)\n    ↓\nSystem config ($BTRACE_HOME/conf/extensions.conf)\n    ↓\nBuilt-in defaults (all enabled, autoload=true)\n```\n\n## Implementation Plan\n\n1. Create ExtensionConfig class to parse and store configuration\n2. Update ExtensionLoader to accept and use ExtensionConfig\n3. Update Main.java to load configuration before initializing extensions\n4. Add configuration file to distribution at conf/extensions.conf (empty/commented)\n5. Document configuration in user guide\n\n## Backward Compatibility\n\n- If no configuration file exists, all extensions are enabled with autoload\n- Existing deployments continue to work without any configuration\n- Configuration is purely additive (opt-in customization)\n\n## Future Enhancements\n\n- Hot reload: Detect configuration file changes and reload extensions\n- JMX integration: Expose extension configuration via JMX for runtime modification\n- Validation: Warn about unknown extension IDs or malformed settings\n"
  },
  {
    "path": "docs/architecture/ExtensionInvokeDynamicBridge.md",
    "content": "# Extension invokedynamic Bridge Architecture\n\n## Overview\n\nThe BTrace extension system uses invokedynamic to bridge between script classloaders and extension classloaders, avoiding bootstrap classloader pollution while maintaining complete extension isolation.\n\n**Key Benefits:**\n- **Clean bootstrap namespace** - Only BTrace core classes in bootstrap, no extension JARs\n- **Extension isolation** - Each extension in its own classloader with shaded dependencies\n- **Security** - Extensions don't have bootstrap-level privileges\n- **Java 8+ compatible** - Works on all supported Java versions (8+)\n\n## Architecture Diagram\n\n```\n┌──────────────────────────────────────┐\n│ BTrace Script                        │\n│ ┌──────────────────────────────────┐ │\n│ │ @Injected MetricsService metrics │ │\n│ │                                  │ │\n│ │ void onMethod() {                │ │\n│ │   metrics.histogram(\"foo\")  ←────┼─┼── INVOKEDYNAMIC call\n│ │ }                                │ │\n│ └──────────────────────────────────┘ │\n│                                      │\n│ Classloader: Anonymous (parent=null)│\n└────────────┬─────────────────────────┘\n             │ delegates to bootstrap\n             ↓\n┌──────────────────────────────────────┐         ┌────────────────────────────┐\n│ Bootstrap ClassLoader                │         │ Extension ClassLoaders     │\n│                                      │         │                            │\n│ ┌─────────────────────────────────┐  │         │ ┌────────────────────────┐ │\n│ │ ExtensionIndy.java              │  │◄────────┼─┤ btrace-metrics         │ │\n│ │                                 │  │ bridge  │ │ - MetricsService.class │ │\n│ │ public static CallSite          │  │         │ │ - HdrHistogram (shaded)│ │\n│ │   bootstrapFieldGet(...) {      │  │         │ └────────────────────────┘ │\n│ │   // Get extension class        │  │         │                            │\n│ │   Class<?> clz =                │  │         │ ┌────────────────────────┐ │\n│ │     bridge.getExtensionClass(); │  │         │ │ btrace-statsd          │ │\n│ │   // Create MethodHandle        │  │         │ │ - (isolated)           │ │\n│ │   return new ConstantCallSite(mh)│ │         │ └────────────────────────┘ │\n│ │ }                               │  │         │                            │\n│ └─────────────────────────────────┘  │         │ ┌────────────────────────┐ │\n│                                      │         │ │ custom-extension       │ │\n│ ┌─────────────────────────────────┐  │         │ │ - (isolated)           │ │\n│ │ ExtensionBridge (interface)     │  │         │ └────────────────────────┘ │\n│ │ - getExtensionClass()           │  │         │                            │\n│ └─────────────────────────────────┘  │         └────────────────────────────┘\n│                                      │                      ▲\n│ ┌─────────────────────────────────┐  │                      │\n│ │ btrace-boot.jar                 │  │                      │\n│ │ - BTraceRuntime                 │  │                      │\n│ │ - BTraceUtils                   │  │                      │\n│ │ - Core annotations              │  │                      │\n│ └─────────────────────────────────┘  │                      │\n└──────────────────────────────────────┘                      │\n             ▲                                                │\n             │ implements                                     │\n             │                                                │\n┌────────────┴─────────────────────┐                          │\n│ btrace-agent                     │                          │\n│                                  │                          │\n│ ┌──────────────────────────────┐ │                          │\n│ │ ExtensionBridgeImpl          │ │                          │\n│ │                              │ │                          │\n│ │ static {                     │ │                          │\n│ │   // Set ExtensionIndy.bridge│ │                          │\n│ │   ExtensionIndy.bridge =     │ │                          │\n│ │     new ExtensionBridgeImpl()│ │                          │\n│ │ }                            │ │                          │\n│ │                              │ │                          │\n│ │ Class<?> getExtensionClass() │ │                          │\n│ │   // Find extension          │ │                          │\n│ │   // Load extension          │─┼──────────────────────────┘\n│ │   // Return class from       │ │\n│ │   // extension CL            │ │\n│ └──────────────────────────────┘ │\n│                                  │\n│ ┌──────────────────────────────┐ │\n│ │ ExtensionLoader              │ │\n│ │ - discoverExtensions()       │ │\n│ │ - load(ExtensionDescriptor)  │ │\n│ │ - findExtensionForService()  │ │\n│ └──────────────────────────────┘ │\n└──────────────────────────────────┘\n```\n\n## Component Details\n\n### 1. ExtensionIndy (btrace-runtime)\n\n**Location:** `btrace-runtime/src/main/java/org/openjdk/btrace/runtime/ExtensionIndy.java`\n\n**Purpose:** Bootstrap methods for invokedynamic extension access\n\n**Key Methods:**\n```java\npublic static CallSite bootstrapFieldGet(\n    MethodHandles.Lookup caller,\n    String fieldName,\n    MethodType type,\n    String serviceClassName,\n    String serviceType,\n    String factoryMethod) throws Exception\n```\n\n**Responsibilities:**\n- Receives invokedynamic bootstrap calls from script bytecode\n- Uses ExtensionBridge to load extension service class\n- Creates MethodHandle for service instantiation\n- Handles both SIMPLE (no-arg) and RUNTIME (BTraceRuntime.Impl param) services\n- Supports both constructors and factory methods\n- Returns ConstantCallSite for zero-overhead subsequent calls\n\n**Error Handling:**\n- Gracefully degrades to null on failure\n- Logs errors but doesn't throw exceptions\n- Matches behavior of failed service instantiation\n\n### 2. ExtensionBridge (btrace-runtime)\n\n**Location:** `btrace-runtime/src/main/java/org/openjdk/btrace/runtime/ExtensionBridge.java`\n\n**Purpose:** Interface for agent-to-runtime classloader bridging\n\n**API:**\n```java\npublic interface ExtensionBridge {\n  Class<?> getExtensionClass(String serviceClassName) throws Exception;\n}\n```\n\n**Why an Interface:**\n- Allows btrace-runtime (bootstrap) to call btrace-agent code\n- Breaks circular dependency (runtime can't depend on agent)\n- Clean separation of concerns\n\n### 3. ExtensionBridgeImpl (btrace-agent)\n\n**Location:** `btrace-agent/src/main/java/org/openjdk/btrace/agent/extension/ExtensionBridgeImpl.java`\n\n**Purpose:** Agent-side implementation of ExtensionBridge\n\n**Initialization:**\n```java\nstatic {\n  try {\n    Class<?> indyClz = Class.forName(\"org.openjdk.btrace.runtime.ExtensionIndy\");\n    ExtensionBridge bridge = new ExtensionBridgeImpl(Main.getExtensionLoader());\n    indyClz.getField(\"bridge\").set(null, bridge);\n  } catch (ClassNotFoundException e) {\n    // Expected for pre-Java 8 or if ExtensionIndy unavailable\n  }\n}\n```\n\n**Responsibilities:**\n- Sets `ExtensionIndy.bridge` field during static initialization\n- Uses ExtensionLoader to find extensions providing requested services\n- Loads extension classes from extension classloaders\n- Ensures extensions are loaded before returning class\n\n### 4. Preprocessor (btrace-instr)\n\n**Location:** `btrace-instr/src/main/java/org/openjdk/btrace/instr/Preprocessor.java`\n\n**Purpose:** Transforms @Injected field references to invokedynamic\n\n**Transformation:**\n```java\n// Before:\nGETSTATIC ScriptClass.metrics : MetricsService\n\n// After:\nINVOKEDYNAMIC bootstrapFieldGet(\n  \"metrics\",                           // field name (debug)\n  \"()Lorg/openjdk/btrace/metrics/MetricsService;\",  // method descriptor\n  ExtensionIndy.bootstrapFieldGet,     // bootstrap method\n  \"org.openjdk.btrace.metrics.MetricsService\",  // service class name\n  \"RUNTIME\",                           // optional type hint (deprecated)\n  \"\"                                   // factory method (empty = constructor)\n) : MetricsService\n```\n\n**Modified Method:**\n```java\nprivate AbstractInsnNode updateInjectedUsage(\n    ClassNode cn, FieldInsnNode fin, InsnList l, LocalVarGenerator lvg)\n```\n\n**Changes:**\n- Removed local variable caching\n- Removed service instantiation bytecode\n- Emits InvokeDynamicInsnNode instead\n- Passes service metadata as bootstrap arguments\n\n### 5. ExtensionLoader (btrace-agent)\n\n**Location:** `btrace-agent/src/main/java/org/openjdk/btrace/agent/extension/ExtensionLoader.java`\n\n**Key Changes:**\n- Avoids `instrumentation.appendToBootstrapClassLoaderSearch(jarFile)`\n- Avoids an eager extension loading loop\n- **Behavior:** Extensions loaded on-demand via invokedynamic\n\n**Impact:**\n- Bootstrap classloader remains clean\n- Extensions only loaded when scripts use them\n- Better resource utilization\n\n## Execution Flow\n\n### Initialization (Agent Startup)\n\n```\n1. Main.agentmain/premain()\n   ↓\n2. ExtensionLoader.discoverExtensions()\n   - Scans extensions/ directory\n   - Creates ExtensionDescriptor for each extension\n   - Stores in availableExtensions map\n   - Does NOT load extensions yet\n   ↓\n3. ExtensionBridgeImpl.<clinit>() (static initializer)\n   - Creates new ExtensionBridgeImpl instance\n   - Sets ExtensionIndy.bridge = instance\n   - Bridge now ready for invokedynamic bootstrap calls\n   ↓\n4. Scripts can now be loaded and compiled\n```\n\n### Script Loading (First Access)\n\n```\n1. Script bytecode contains:\n   INVOKEDYNAMIC bootstrapFieldGet(...) : MetricsService\n   ↓\n2. JVM calls ExtensionIndy.bootstrapFieldGet()\n   (first time for this callsite)\n   ↓\n3. ExtensionIndy.bootstrapFieldGet():\n   a. Call bridge.getExtensionClass(\"org.openjdk.btrace.metrics.MetricsService\")\n   ↓\n4. ExtensionBridgeImpl.getExtensionClass():\n   a. Call loader.findExtensionForService(serviceClassName)\n   b. If ext.isLoaded() == false:\n      - loader.load(ext)  // Loads extension JAR into ExtensionClassLoader\n   c. extClassLoader.loadClass(serviceClassName)\n   d. Return Class<?> to bootstrap method\n   ↓\n5. ExtensionIndy.bootstrapFieldGet() (continued):\n   a. Create MethodHandle for service instantiation:\n      - Auto-detect constructor or factory\n      - Initialize extensions via Extension.initialize(ExtensionContext) when first accessed\n   b. Return new ConstantCallSite(methodHandle)\n   ↓\n6. JVM caches ConstantCallSite\n   ↓\n7. Subsequent calls to same INVOKEDYNAMIC:\n   - Use cached CallSite (zero overhead)\n   - MethodHandle directly instantiates service\n   - No bootstrap method re-execution\n```\n\n### Subsequent Field Access (Same Script)\n\n```\n1. Script executes: metrics.histogram(\"foo\")\n   ↓\n2. INVOKEDYNAMIC instruction\n   ↓\n3. JVM uses cached CallSite (no bootstrap)\n   ↓\n4. MethodHandle executes:\n   - Instantiates MetricsService\n   - Returns service instance\n   ↓\n5. INVOKEVIRTUAL MetricsService.histogram(String)\n   - Normal virtual dispatch\n   - JVM resolves from actual object class\n   - Extension method executes\n```\n\n## Performance Characteristics\n\n### First Access\n\n**Overhead:**\n- Bootstrap method execution: ~1-5ms\n  - Extension class loading (if not already loaded)\n  - MethodHandle creation\n  - CallSite creation\n\n**One-time cost per @Injected field per script**\n\n### Subsequent Access\n\n**Overhead:** Zero (compared to direct method call)\n- JVM optimizes ConstantCallSite to direct call\n- Identical performance to pre-invokedynamic approach\n- JIT compiler inlines if possible\n\n### Memory\n\n**Before (Bootstrap Classpath):**\n- All extension JARs in bootstrap: ~5-10MB per extension\n- Permanent heap allocation\n- Visible to all scripts and JVM internals\n\n**After (invokedynamic Bridge):**\n- Only loaded extensions in memory\n- Extension classloaders eligible for GC when scripts unload\n- Clean namespace separation\n\n## Extension Types and Instantiation\n\n### Extension Instances (No-arg)\n\nPreferred pattern: extensions expose a public no-arg constructor and receive\ntheir runtime context via `Extension.initialize(ExtensionContext)`.\n\n**Constructor Example:**\n```java\npublic class MyExtension extends Extension {\n  public MyExtension() {\n    // No-arg constructor\n  }\n}\n```\n\n**MethodHandle Creation:**\n```java\nMethodHandle constructor =\n  MethodHandles.publicLookup().findConstructor(\n    serviceClass,\n    MethodType.methodType(void.class));\n```\n\nFactory methods are also supported but less common in the new model.\n\n**MethodHandle Creation:**\n```java\nMethodHandle factory =\n  MethodHandles.publicLookup().findStatic(\n    serviceClass,\n    \"getInstance\",\n    MethodType.methodType(serviceClass));\n```\n\n### Runtime-Aware Initialization\n\nIf an extension needs access to runtime context, override `initialize(ExtensionContext)`\nin your subclass of `Extension`. The bridge calls it after construction.\n\n**Initialization Example:**\n```java\npublic class MyExtension extends Extension {\n  @Override\n  public void initialize(ExtensionContext ctx) {\n    super.initialize(ctx);\n    // Use ctx as needed\n  }\n}\n```\n\n**MethodHandle Creation:**\n```java\nClass<?> runtimeImplClass =\n  Class.forName(\"org.openjdk.btrace.runtime.BTraceRuntime$Impl\");\n\nMethodHandle constructor =\n  MethodHandles.publicLookup().findConstructor(\n    serviceClass,\n    MethodType.methodType(void.class, runtimeImplClass));\n\n// Bind BTraceRuntime.enter() as first argument\nMethodHandle getRuntimeImpl =\n  MethodHandles.publicLookup().findStatic(\n    BTraceRuntime.class,\n    \"enter\",\n    MethodType.methodType(runtimeImplClass));\n\nmh = MethodHandles.filterReturnValue(getRuntimeImpl, constructor);\n```\n\n## Classloader Hierarchy\n\n### Script Classloader\n\n```java\n// In BTraceRuntimeImpl_8.defineClass()\nClassLoader loader = new ClassLoader(null) {};  // parent = null\nClass<?> cl = unsafe.defineClass(name, code, 0, code.length, loader, null);\n```\n\n**Parent:** null (delegates directly to bootstrap)\n**Visibility:** Only bootstrap classes\n**Impact:** Scripts can only see classes in bootstrap classpath\n\n### Extension Classloader\n\n```java\n// In ExtensionLoader.load()\nExtensionClassLoader classLoader = new ExtensionClassLoader(\n  extensionId,\n  extensionVersion,\n  new URL[] {jarUrl},\n  parentClassLoader  // BTrace boot classloader\n);\n```\n\n**Parent:** BTrace boot classloader (btrace-boot.jar)\n**Visibility:** Extension JAR + BTrace core APIs\n**Isolation:** Each extension in separate classloader\n\n**Shaded Dependencies:**\n- Extensions use shadow plugin to shade dependencies\n- Prevents version conflicts between extensions\n- Example: btrace-metrics shades HdrHistogram\n\n### Classloader Delegation\n\n```\nScript Class\n├── parent = null → Bootstrap ClassLoader\n│   ├── JRE system classes\n│   ├── btrace-boot.jar (BTraceRuntime, annotations)\n│   └── ExtensionIndy.class\n│\nExtensionClassLoader (per extension)\n├── parent = BTrace Boot ClassLoader\n│   └── btrace-boot.jar classes\n├── Extension JAR classes\n└── Shaded dependencies\n```\n\n**invokedynamic bridges the gap:**\n- Script sees only bootstrap\n- Bootstrap method accesses extension via bridge\n- MethodHandle allows cross-classloader calls\n\n## Java Version Compatibility\n\n### Java 8+\n\n**invokedynamic features used:**\n- `INVOKEDYNAMIC` instruction (Java 7+)\n- `MethodHandles` (Java 7+)\n- `CallSite` / `ConstantCallSite` (Java 7+)\n- `Handle` (Java 7+)\n\n**NOT used:**\n- Hidden classes (`Lookup.defineHiddenClass`) - Java 15+ only\n- VarHandles - Java 9+ only\n\n**Result:** Works on all BTrace-supported Java versions (8+)\n\n### Comparison with Indy.java\n\n**Indy.java (probe handlers):**\n- Uses hidden classes (Java 15+ only)\n- Creates dynamic hidden classes at link time\n- Complex nested class generation\n\n**ExtensionIndy.java (extensions):**\n- Uses standard classloading (Java 8+)\n- Loads classes from extension classloaders\n- Simple MethodHandle creation\n\n## Error Handling and Debugging\n\n### Bootstrap Method Failures\n\n**Causes:**\n- Extension not found\n- Extension class loading failure\n- Constructor/factory method not found\n- Runtime instantiation error\n\n**Behavior:**\n```java\ntry {\n  // Load class and create MethodHandle\n} catch (Throwable t) {\n  // Graceful degradation: return null\n  mh = MethodHandles.constant(type.returnType(), null);\n}\nreturn new ConstantCallSite(mh);\n```\n\n**Impact:**\n- Script continues execution\n- Service field is null\n- NPE on first usage (matches current behavior)\n\n### Debugging\n\n**Enable logging:**\n```\n-Dorg.slf4j.simpleLogger.log.org.openjdk.btrace.agent.extension=DEBUG\n-Dorg.slf4j.simpleLogger.log.org.openjdk.btrace.runtime.ExtensionIndy=DEBUG\n```\n\n**Logs show:**\n- Extension discovery\n- Extension loading\n- Service class resolution\n- MethodHandle creation\n\n**Bytecode inspection:**\n```bash\njavap -v ScriptClass.class | grep -A 5 INVOKEDYNAMIC\n```\n\n**Shows:**\n- Bootstrap method reference\n- Bootstrap arguments\n- Method descriptor\n\n## Migration from Bootstrap Classpath Approach\n\n### Before\n\n**ExtensionLoader.load():**\n```java\nif (instrumentation != null) {\n  JarFile jarFile = new JarFile(descriptor.getJarPath().toFile());\n  instrumentation.appendToBootstrapClassLoaderSearch(jarFile);\n}\n```\n\n**Preprocessor.updateInjectedUsage():**\n```java\n// Create local variable\nint varIdx = lvg.newVar(implType);\n// Emit instantiation bytecode\ntoInsert.add(new TypeInsnNode(Opcodes.NEW, implType.getInternalName()));\ntoInsert.add(new InsnNode(Opcodes.DUP));\ntoInsert.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, ...));\n// Store in local variable\ntoInsert.add(new VarInsnNode(Opcodes.ASTORE, varIdx));\n```\n\n### After\n\n**ExtensionLoader.load():**\n```java\n// Extension classes accessed via invokedynamic bridge\n// (no bootstrap classpath pollution)\n```\n\n**Preprocessor.updateInjectedUsage():**\n```java\n// Emit invokedynamic instruction\nInvokeDynamicInsnNode indyInsn = new InvokeDynamicInsnNode(\n  fieldName,\n  methodDescriptor,\n  bootstrapHandle,\n  serviceClassName,\n  serviceType,\n  factoryMethod);\n```\n\n### Compatibility\n\n**Existing scripts:** No changes required\n- Same @Injected annotation\n- Same field types\n- Same usage patterns\n\n**Existing extensions:** No changes required\n- Same service classes\n- Same constructors/factories\n- Same MANIFEST.MF metadata\n\n**Behavioral changes:** None\n- Extension loading now on-demand\n- Performance characteristics unchanged\n- Error handling identical\n\n## Security Implications\n\n### Bootstrap Classloader Access\n\n**Before:**\n- Extensions had bootstrap-level privileges\n- Could access JVM internals\n- Could interfere with system classes\n\n**After:**\n- Extensions in isolated classloaders\n- Limited to parent visibility (BTrace boot)\n- Cannot access bootstrap internals\n\n### MethodHandle Security\n\n**MethodHandles.publicLookup():**\n- Only creates handles for public members\n- Respects Java access control\n- Cannot access private/protected methods\n\n**Lookup Context:**\n- Bootstrap method has caller's lookup\n- Could create privileged handles\n- Current implementation uses publicLookup() for safety\n\n## Testing\n\n### Unit Tests\n\n**ExtensionIndy:**\n- Test bootstrap method with mock bridge\n- Test SIMPLE vs RUNTIME services\n- Test constructor vs factory instantiation\n- Test error handling\n\n**ExtensionBridgeImpl:**\n- Test extension finding\n- Test class loading\n- Test extension loading on demand\n\n### Integration Tests\n\n**MetricsTest:**\n- Uses @Injected MetricsService\n- Verifies invokedynamic bootstrap execution\n- Verifies service instantiation\n- Verifies method calls work\n\n**Verification:**\n```bash\n# Check bytecode contains INVOKEDYNAMIC\njavap -v integration-tests/build/classes/java/test/MetricsTest.class | grep INVOKEDYNAMIC\n\n# Check extension NOT in bootstrap\njcmd <pid> VM.class_hierarchy | grep -v btrace-metrics\n```\n\n## Future Enhancements\n\n### 1. Extension API/Impl Split\n\n**Concept:**\n- `btrace-metrics-api.jar` → bootstrap (interfaces only)\n- `btrace-metrics-impl.jar` → extension CL (implementations)\n\n**Benefits:**\n- Cleaner verification\n- Smaller bootstrap JAR\n- Better security boundaries\n\n### 2. Service Caching\n\n**Current:** Each invokedynamic creates new instance\n**Enhancement:** Cache service instances per script\n\n**Implementation:**\n```java\n// In ExtensionIndy\nprivate static final Map<String, Object> instanceCache = new ConcurrentHashMap<>();\n\n// In bootstrapFieldGet()\nString cacheKey = caller.lookupClass().getName() + \":\" + serviceClassName;\nObject cached = instanceCache.get(cacheKey);\nif (cached != null) {\n  return new ConstantCallSite(MethodHandles.constant(type.returnType(), cached));\n}\n```\n\n### 3. Hot Reload Support\n\n**Challenge:** Extension updates require agent restart\n**Enhancement:** Use MutableCallSite instead of ConstantCallSite\n\n**Implementation:**\n```java\npublic static CallSite bootstrapFieldGet(...) {\n  MethodHandle mh = createServiceHandle(...);\n  return new MutableCallSite(mh);  // Allows invalidation\n}\n\n// On extension reload:\npublic static void invalidateExtension(String extensionId) {\n  // Find all MutableCallSites for this extension\n  // Call MutableCallSite.setTarget() with new MethodHandle\n}\n```\n\n## Summary\n\nThe invokedynamic extension bridge provides:\n\n✅ **Clean bootstrap namespace** - Only BTrace core in bootstrap\n✅ **Extension isolation** - Each extension in own classloader\n✅ **Java 8+ compatible** - No Java 15+ features required\n✅ **Zero performance overhead** - After first call\n✅ **Backward compatible** - No script changes required\n✅ **Better security** - Extensions lack bootstrap privileges\n✅ **On-demand loading** - Extensions loaded when needed\n\nThis architecture enables scalable, secure, and performant extension loading while maintaining full compatibility with existing BTrace scripts and extensions.\n"
  },
  {
    "path": "docs/architecture/ExtensionManifestFormat.md",
    "content": "# BTrace Extension MANIFEST.MF Format\n\n## Overview\n\nThis document defines the MANIFEST.MF attribute format for BTrace extensions, replacing the previous `btrace-extension.properties` file.\n\n## Rationale\n\nUsing MANIFEST.MF for extension metadata provides:\n- **Standard Java mechanism** - Already parsed by JVM and tools\n- **OSGi precedent** - Follows established patterns from OSGi bundles\n- **Single source of truth** - Build tools already generate MANIFEST.MF\n- **Less maintenance** - No separate properties file to manage\n\n## Attribute Mapping\n\n### From Properties Format\n\n```properties\nextension.id=btrace-metrics\nextension.version=2.3.0\nextension.name=BTrace Metrics\nextension.description=High-performance metrics...\nbtrace.api.version=2.3+\njava.version=8+\nservices=org.openjdk.btrace.metrics.MetricsService\nrequires.extensions=btrace-core\nshaded.packages=org.HdrHistogram->org.openjdk.btrace.metrics.shaded.hdrhistogram\n```\n\n### To MANIFEST.MF Format\n\n```\nBTrace-Extension-Id: btrace-metrics\nBTrace-Extension-Version: 2.3.0\nBTrace-Extension-Name: BTrace Metrics\nBTrace-Extension-Description: High-performance metrics with HdrHistogram\n for percentiles and lock-free statistics\nBTrace-API-Version: 2.3+\nBTrace-Java-Version: 8+\nBTrace-Extension-Services: org.openjdk.btrace.metrics.MetricsService\nBTrace-Extension-Requires: btrace-core\nBTrace-Shaded-Packages: org.HdrHistogram->org.openjdk.btrace.metrics.sh\n aded.hdrhistogram,com.clearspring.analytics->org.openjdk.btrace.metrics\n .shaded.clearspring\nBTrace-Extension-Permissions: NETWORK,THREADS\n```\n\n## Attribute Definitions\n\n### Required Attributes\n\n**BTrace-Extension-Id**\n- Format: lowercase-with-hyphens\n- Example: `btrace-metrics`\n- Description: Unique identifier for the extension\n\n**BTrace-Extension-Version**\n- Format: semantic version (major.minor.patch[-qualifier])\n- Example: `2.3.0`, `2.3.0-SNAPSHOT`\n- Description: Extension version for conflict resolution\n\n### Optional Attributes\n\n**BTrace-Extension-Name**\n- Format: human-readable string\n- Example: `BTrace Metrics`\n- Description: Display name for the extension\n\n**BTrace-Extension-Description**\n- Format: multi-line text (continuation with leading space)\n- Example: `High-performance metrics with HdrHistogram`\n- Description: Detailed description of extension functionality\n\n**BTrace-API-Version**\n- Format: version range (major.minor+)\n- Example: `2.3+` (requires BTrace API 2.3 or higher)\n- Description: Required BTrace API version\n\n**BTrace-Java-Version**\n- Format: version number (8+, 11+, etc.)\n- Example: `8+`\n- Description: Minimum Java version required\n\n**BTrace-Extension-Services**\n- Format: comma-separated fully qualified class names\n- Example: `org.openjdk.btrace.metrics.MetricsService,org.openjdk.btrace.metrics.StatsService`\n- Description: Service classes provided by this extension\n\n**BTrace-Extension-Requires**\n- Format: comma-separated extension IDs\n- Example: `btrace-core,btrace-util`\n- Description: Other extensions required by this extension\n\n**BTrace-Shaded-Packages**\n- Format: comma-separated package mappings (original->shaded)\n- Example: `org.HdrHistogram->org.openjdk.btrace.metrics.shaded.hdrhistogram`\n- Description: Package relocation mappings for shaded dependencies\n\n## MANIFEST.MF Line Continuation\n\nPer JAR specification, manifest attributes longer than 72 bytes must be continued on the next line with a leading space:\n\n```\nBTrace-Extension-Description: This is a very long description that excee\n ds the 72-byte limit and must be continued on the next line with a lead\n ing space character.\n```\n\n## Backward Compatibility\n\nThe extension loader supports both formats:\n\n1. Check for MANIFEST.MF attributes first\n2. Fall back to `btrace-extension.properties` if MANIFEST attributes not found\n3. Log deprecation warning if using properties file\n\n## Gradle Configuration\n\nExtensions should configure MANIFEST.MF generation in build.gradle:\n\n```gradle\njar {\n  manifest {\n    attributes(\n      'BTrace-Extension-Id': 'btrace-metrics',\n      'BTrace-Extension-Version': project.version,\n      'BTrace-Extension-Name': 'BTrace Metrics',\n      'BTrace-Extension-Description': 'High-performance metrics...',\n      'BTrace-API-Version': '2.3+',\n      'BTrace-Java-Version': '8+',\n      'BTrace-Extension-Services': 'org.openjdk.btrace.metrics.MetricsService',\n      'BTrace-Shaded-Packages': 'org.HdrHistogram->org.openjdk.btrace.metrics.shaded.hdrhistogram'\n    )\n  }\n}\n```\n\n## Migration Path\n\n1. ✅ Design MANIFEST.MF format (this document)\n2. Update ExtensionMetadata parser to read MANIFEST.MF\n3. Update btrace-metrics build.gradle to generate MANIFEST attributes\n4. Test with both formats for backward compatibility\n5. Update documentation\n6. Deprecate btrace-extension.properties (remove in future release)\n**BTrace-Extension-Permissions**\n- Format: comma-separated permission names\n- Example: `NETWORK,THREADS,FILE_WRITE`\n- Description: Permissions required by the extension implementation. Automatically inferred by the build plugin via code scanning, with optional overrides in Gradle.\n"
  },
  {
    "path": "docs/architecture/ExtensionStorageDesign.md",
    "content": "# BTrace Extension Storage Design\n\n## Overview\n\nThis document describes the design for BTrace extension storage and loading mechanism. The goal is to move extensions from the boot JAR to a dedicated extension system with built-in and user-configurable locations.\n\n## Current State\n\nCurrently, extensions (like btrace-metrics) are packaged into the boot JAR (`btrace-boot.jar`) along with core BTrace runtime classes. This approach has several limitations:\n\n1. **No Extension Isolation**: Extensions are mixed with core runtime code\n2. **No Version Management**: Can't have multiple versions of an extension\n3. **No Dynamic Loading**: All extensions loaded at startup, even if unused\n4. **Deployment Friction**: Adding new extensions requires rebuilding the distribution\n5. **User Extensions**: No mechanism for users to add custom extensions\n\n## Design Goals\n\n1. **Separation**: Extensions stored separately from core runtime\n2. **Discoverability**: Automatic discovery of built-in and user extensions\n3. **Configuration**: User-configurable extension locations\n4. **Lazy Loading**: Load extensions only when referenced in scripts\n5. **Isolation**: Extension classloading isolation to avoid conflicts\n6. **Metadata**: Extension metadata for versioning and dependencies\n\n## Directory Structure\n\n### Distribution Layout\n\n```\nBTRACE_HOME/\n├── bin/\n│   ├── btrace\n│   └── btracec\n├── libs/\n│   ├── btrace-agent.jar\n│   ├── btrace-boot.jar       # Core runtime only, no extensions\n│   ├── btrace-client.jar\n│   └── extensions/            # Built-in extensions directory\n│       ├── btrace-metrics-2.3.0.jar\n│       ├── btrace-statsd-2.3.0.jar\n│       └── Readme.md\n└── docs/\n    └── ...\n```\n\n### User Extension Locations\n\nExtensions are discovered in the following order (later locations override earlier):\n\n1. **Built-in**: `BTRACE_HOME/extensions/`\n2. **System**: `/etc/btrace/extensions/` (Unix) or `%PROGRAMDATA%\\btrace\\extensions\\` (Windows)\n3. **User**: `~/.btrace/extensions/`\n4. **Environment**: `$BTRACE_EXT_PATH` (colon-separated paths)\n5. **Command-line**: `--ext-path <path>` (btrace command)\n6. **Script-local**: `./.btrace/extensions/` (relative to script location)\n\n## Extension Structure\n\n### Extension JAR Layout\n\n```\nbtrace-metrics-2.3.0.jar\n├── META-INF/\n│   ├── MANIFEST.MF\n│   ├── btrace-extension.properties      # Extension metadata\n│   └── services/\n│       └── org.openjdk.btrace.core.extensions.Extension\n├── org/openjdk/btrace/metrics/\n│   ├── MetricsService.class\n│   ├── histogram/\n│   └── stats/\n└── ... (shaded dependencies)\n```\n\n### Extension Metadata (`btrace-extension.properties`)\n\n```properties\n# Extension identity\nextension.id=btrace-metrics\nextension.version=2.3.0\nextension.name=BTrace Metrics\nextension.description=High-performance metrics with HdrHistogram\n\n# API compatibility\nbtrace.api.version=2.3+\njava.version=8+\n\n# Service providers (optional, can also use META-INF/services)\nservices=org.openjdk.btrace.metrics.MetricsService\n\n# Dependencies on other extensions (optional)\nrequires.extensions=\n\n# Shadowed packages (for conflict detection)\nshaded.packages=org.HdrHistogram->org.openjdk.btrace.metrics.shaded.hdrhistogram,\\\n                com.clearspring.analytics->org.openjdk.btrace.metrics.shaded.clearspring\n```\n\n## Extension Loading Mechanism\n\n### 1. Discovery Phase (on Agent Startup)\n\n```java\npublic class ExtensionLoader {\n    private final List<ExtensionRepository> repositories;\n\n    // Scan all configured locations\n    public List<ExtensionDescriptor> discoverExtensions() {\n        List<ExtensionDescriptor> extensions = new ArrayList<>();\n\n        for (ExtensionRepository repo : repositories) {\n            extensions.addAll(repo.scan());\n        }\n\n        // Resolve conflicts (latest version wins)\n        return resolveExtensions(extensions);\n    }\n}\n```\n\n### 2. Lazy Loading (on Script Compilation)\n\nWhen the compiler encounters an `@Injected` service:\n\n```java\n// In Compiler.java\nprivate void loadRequiredExtensions(List<String> serviceTypes) {\n    for (String serviceType : serviceTypes) {\n        ExtensionDescriptor ext = extensionLoader.findExtensionForService(serviceType);\n        if (ext != null && !ext.isLoaded()) {\n            extensionLoader.load(ext);\n        }\n    }\n}\n```\n\n### 3. ClassLoader Hierarchy\n\n```\nBootstrap ClassLoader\n    |\nSystem ClassLoader\n    |\nBTrace Boot ClassLoader (btrace-boot.jar)\n    |\n    +-- Extension ClassLoader 1 (btrace-metrics)\n    |\n    +-- Extension ClassLoader 2 (btrace-statsd)\n    |\n    +-- ...\n    |\nBTrace Script ClassLoader (compiled script)\n```\n\nEach extension gets its own classloader for isolation, but they can see:\n- Bootstrap classes\n- BTrace core API classes\n- Their own classes and shaded dependencies\n\n## Configuration\n\n### Agent Configuration (`btrace.conf`)\n\n```properties\n# Extension directories (colon-separated on Unix, semicolon on Windows)\nextension.path=${BTRACE_HOME}/extensions:${HOME}/.btrace/extensions\n\n# Extension loading behavior\nextension.lazy-load=true\nextension.fail-on-missing=false\nextension.conflict-resolution=latest-version\n\n# Extension-specific settings\nextension.btrace-metrics.enabled=true\nextension.btrace-statsd.enabled=true\n```\n\n### Environment Variables\n\n```bash\n# Override extension path\nexport BTRACE_EXT_PATH=\"/opt/btrace-extensions:/usr/local/btrace/ext\"\n\n# Disable lazy loading (load all extensions at startup)\nexport BTRACE_EXT_LAZY_LOAD=false\n```\n\n### Command-line Options\n\n```bash\n# Specify additional extension directories\nbtrace --ext-path /custom/extensions PID script.java\n\n# Disable built-in extensions\nbtrace --no-builtin-ext PID script.java\n\n# Enable specific extensions only\nbtrace --ext btrace-metrics,btrace-statsd PID script.java\n```\n\n## Extension API\n\n### Creating an Extension\n\n1. **Implement Service Interface**:\n```java\npackage com.example.myext;\n\nimport org.openjdk.btrace.core.extensions.Extension;\n\npublic class MyExtensionService extends Extension {\n    @Override\n    public void onStart(BTraceRuntime runtime) {\n        // Initialize extension\n    }\n}\n```\n\n2. **Register Service**:\nNo SPI file required. The Gradle plugin writes manifest attributes (BTrace-Extension-Services).\n```\ncom.example.myext.MyExtensionService\n```\n\n3. **Add Metadata**:\nCreate `META-INF/btrace-extension.properties`:\n```properties\nextension.id=my-extension\nextension.version=1.0.0\nbtrace.api.version=2.3+\n```\n\n4. **Build JAR**:\n```gradle\nshadowJar {\n    // Shade dependencies to avoid conflicts\n    relocate 'com.external.lib', 'com.example.myext.shaded.lib'\n}\n```\n\n5. **Deploy**:\n```bash\ncp my-extension-1.0.0.jar $BTRACE_HOME/extensions/\n# or\ncp my-extension-1.0.0.jar ~/.btrace/ext/\n```\n\n## Extension Repositories\n\n### Local File System Repository\n\n```java\npublic class FileSystemExtensionRepository implements ExtensionRepository {\n    private final Path extensionDir;\n\n    @Override\n    public List<ExtensionDescriptor> scan() {\n        List<ExtensionDescriptor> extensions = new ArrayList<>();\n\n        try (DirectoryStream<Path> stream = Files.newDirectoryStream(extensionDir, \"*.jar\")) {\n            for (Path jar : stream) {\n                ExtensionDescriptor desc = parseExtension(jar);\n                if (desc != null) {\n                    extensions.add(desc);\n                }\n            }\n        }\n\n        return extensions;\n    }\n}\n```\n\n### Future: Remote Repository (Maven-like)\n\n```properties\n# In btrace.conf\nextension.repository.url=https://extensions.btrace.io/repository\nextension.repository.cache=${HOME}/.btrace/cache\n```\n\n## Migration Path\n\n### Phase 1: Dual Mode (Current + New)\n- Keep extensions in boot JAR for backward compatibility\n- Add new extension loading mechanism\n- Extensions can be discovered from both locations\n\n### Phase 2: Deprecation\n- Move built-in extensions to `extensions/` in distribution\n- Boot JAR checks if extension exists in extensions/ before loading from itself\n- Log deprecation warnings\n\n### Phase 3: Removal\n- Remove extensions from boot JAR\n- Only load from extension directories\n\n## Implementation Plan\n\n### Stage 1: Extension Discovery (1-2 days)\n- [ ] Create `ExtensionDescriptor` class\n- [ ] Create `ExtensionRepository` interface and FileSystemRepository\n- [ ] Implement extension scanning and metadata parsing\n- [ ] Add extension.properties parsing\n\n### Stage 2: Extension Loading (2-3 days)\n- [ ] Create `ExtensionClassLoader` with proper parent delegation\n- [ ] Implement lazy loading mechanism\n- [ ] Add extension lifecycle management (load/unload)\n- [ ] Handle ServiceLoader integration with extensions\n\n### Stage 3: Configuration (1-2 days)\n- [ ] Add configuration file support\n- [ ] Environment variable handling\n- [ ] Command-line argument parsing\n- [ ] Extension path resolution\n\n### Stage 4: Integration (2-3 days)\n- [ ] Integrate with compiler (detect required services)\n- [ ] Integrate with agent (load extensions)\n- [ ] Update verifier to work with extension classloaders\n- [ ] Update build to create ext/ directory structure\n\n### Stage 5: Migration (1-2 days)\n- [ ] Move btrace-metrics to ext/ directory\n- [ ] Move btrace-statsd to ext/ directory\n- [ ] Update documentation\n- [ ] Update integration tests\n\n### Stage 6: Testing & Documentation (2-3 days)\n- [ ] Unit tests for extension loading\n- [ ] Integration tests with multiple extensions\n- [ ] Test extension conflicts and resolution\n- [ ] Developer guide for creating extensions\n- [ ] User guide for installing extensions\n\n**Total Estimated Effort**: 9-15 days\n\n## Security Considerations\n\n1. **Extension Verification**:\n   - Check JAR signatures\n   - Validate extension metadata\n   - Sandbox extension code (SecurityManager)\n\n2. **Trusted Locations**:\n   - Built-in extensions (BTRACE_HOME) are trusted\n   - User extensions require explicit trust or signature\n\n3. **Classloading Isolation**:\n   - Extensions cannot access each other's classes\n   - Extensions cannot override core BTrace classes\n\n4. **Resource Limits**:\n   - Limit memory usage per extension\n   - Timeout for extension initialization\n\n## Performance Considerations\n\n1. **Lazy Loading**: Load extensions only when needed by scripts\n2. **Caching**: Cache extension metadata to avoid repeated JAR scanning\n3. **Parallel Loading**: Load independent extensions in parallel\n4. **Minimal Overhead**: Discovery should add <100ms to agent startup\n\n## Backward Compatibility\n\n1. **Boot JAR Fallback**: If extension not found in ext/, check boot JAR\n2. **Service Discovery**: Support both old and new service loading\n3. **Configuration**: Old configurations continue to work\n4. **Scripts**: Existing scripts work without modification\n\n## Open Questions\n\n1. **Extension Dependencies**: How do extensions depend on each other?\n2. **Version Conflicts**: What happens when script needs different versions?\n3. **Extension Updates**: Hot-reload extensions without restarting agent?\n4. **Distribution**: Package extensions separately or all-in-one?\n5. **Remote Loading**: Allow downloading extensions from remote repositories?\n\n## References\n\n- [Java ServiceLoader Documentation](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html)\n- [OSGi Bundle Format](https://docs.osgi.org/specification/osgi.core/7.0.0/framework.module.html)\n- [Maven Extension Mechanism](https://maven.apache.org/guides/mini/guide-using-extensions.html)\n"
  },
  {
    "path": "docs/architecture/MaskedJarArchitecture.md",
    "content": "# Masked JAR Architecture\n\n## Overview\n\nBTrace uses a single-JAR distribution (`btrace.jar`) with a **classdata masking** technique to minimize bootstrap classloader pollution. This architecture packs agent, client, and shared classes into one JAR while keeping only essential API classes visible to the bootstrap classloader.\n\nThe key insight: files with a `.classdata` extension are invisible to the JVM's built-in classloading, so non-bootstrap classes can coexist in the same JAR without leaking into the bootstrap classloader.\n\n## Problem\n\nTraditional Java agents add their entire JAR to the bootstrap classloader via `Boot-Class-Path: .` in the manifest. For BTrace, this would expose ~1500+ classes (ASM, compiler, instrumentation engine, client) to every class in the JVM. This causes:\n\n- Namespace pollution (classes visible where they shouldn't be)\n- Potential conflicts with application dependencies (e.g., different ASM versions)\n- Increased memory footprint in the bootstrap classloader\n\nThe previous multi-JAR approach (`btrace-agent.jar`, `btrace-boot.jar`, `btrace-client.jar`) solved this by splitting classes across JARs but introduced hardcoded co-location assumptions that broke alternative distribution methods like jbang and Maven repositories.\n\n## Architecture\n\n### JAR Structure\n\n```\nbtrace.jar (~2.9 MB)\n├── org/openjdk/btrace/boot/*.class             # Entry point (Loader, MaskedClassLoader, MaskedJarUtils)\n├── org/openjdk/btrace/core/*.class             # Bootstrap: core API (~42 classes)\n├── org/openjdk/btrace/core/extensions/*.class  # Bootstrap: extension API\n├── org/openjdk/btrace/core/types/*.class       # Bootstrap: type definitions\n├── org/openjdk/btrace/core/jfr/*.class         # Bootstrap: JFR integration\n├── org/openjdk/btrace/runtime/*.class          # Bootstrap: runtime support\n├── org/openjdk/btrace/libs/org/slf4j/**        # Bootstrap: relocated SLF4J\n├── META-INF/btrace/agent/*.classdata           # Masked: agent classes\n├── META-INF/btrace/client/*.classdata          # Masked: client classes\n├── META-INF/btrace/shared/*.classdata          # Masked: shared classes (ASM, protocol, etc.)\n└── META-INF/MANIFEST.MF\n```\n\n**Bootstrap classes** (~112 total): Only the core API, runtime support, and SLF4J logging are stored as regular `.class` files. These are visible to the bootstrap classloader because the manifest declares `Boot-Class-Path: .`.\n\n**Masked classes** (~1600+): Agent, client, and shared classes are stored as `.classdata` files under `META-INF/btrace/`. The JVM's class loading ignores these files entirely. They are loaded on demand by `MaskedClassLoader`.\n\n### Manifest\n\n```\nPremain-Class: org.openjdk.btrace.boot.Loader\nAgent-Class: org.openjdk.btrace.boot.Loader\nMain-Class: org.openjdk.btrace.boot.Loader\nCan-Redefine-Classes: true\nCan-Retransform-Classes: true\nBoot-Class-Path: .\nBTrace-Agent-Main: org.openjdk.btrace.agent.Main\nBTrace-Client-Main: org.openjdk.btrace.client.Main\n```\n\n`Loader` is the single entry point for all three modes. The actual agent/client main classes are specified as manifest attributes and loaded reflectively via `MaskedClassLoader`.\n\n## Components\n\n### btrace-boot Module\n\n**Location:** `btrace-boot/`\n\nContains three classes, all loaded by the bootstrap classloader:\n\n#### Loader (`org.openjdk.btrace.boot.Loader`)\n\nEntry point for all three modes:\n\n| Mode | Entry Method | Invocation |\n|------|-------------|------------|\n| Load-time agent | `premain(String, Instrumentation)` | `-javaagent:btrace.jar` |\n| Dynamic attach | `agentmain(String, Instrumentation)` | `VirtualMachine.loadAgent()` |\n| Client CLI | `main(String[])` | `java -jar btrace.jar` |\n\nEach mode creates a `MaskedClassLoader` for the appropriate section (agent or client), loads the main class from the manifest attribute, and invokes it reflectively.\n\n**Agent mode classloader hierarchy:**\n```\nBootstrap CL (core API, runtime, Loader)\n    └── MaskedClassLoader[agent] (parent=null)\n            Loads from: META-INF/btrace/agent/*.classdata\n            Fallback:   META-INF/btrace/shared/*.classdata\n```\n\nUsing `null` as the parent ensures bootstrap-visible classes (like `BTraceRuntimeAccess`) are loaded from the bootstrap classloader rather than the agent's classloader. This is critical because probe classes—defined via the bootstrap classloader—must see the same class instances the agent uses.\n\n**Client mode classloader hierarchy:**\n```\nBootstrap CL (core API, runtime, Loader)\n    └── System CL\n        └── MaskedClassLoader[client] (parent=System CL)\n                Loads from: META-INF/btrace/client/*.classdata\n                Fallback:   META-INF/btrace/shared/*.classdata\n```\n\n#### MaskedClassLoader (`org.openjdk.btrace.boot.MaskedClassLoader`)\n\nA `URLClassLoader` subclass that loads classes from `.classdata` files. The lookup order for `findClass(name)`:\n\n1. Check section-specific path: `META-INF/btrace/{section}/{class-path}.classdata`\n2. Check shared path: `META-INF/btrace/shared/{class-path}.classdata`\n3. Throw `ClassNotFoundException` (delegates to parent via standard classloader contract)\n\nResource loading (`findResource`, `getResourceAsStream`) follows the same pattern: section-specific first, then shared, then the JAR root.\n\n#### MaskedJarUtils (`org.openjdk.btrace.boot.MaskedJarUtils`)\n\nUtility class for detecting masked JARs. A JAR is identified as masked by the presence of a `META-INF/btrace/shared/` entry. Used by `Client.java` and integration tests to detect whether they are running from a masked JAR or the legacy multi-JAR layout.\n\n### btrace-bootstrap Module\n\n**Location:** `btrace-bootstrap/`\n\nA build-only module that defines which classes belong in the bootstrap section via a `bootIncludes` filter closure. This filter is used by the `btraceJar` task in `btrace-dist/build.gradle` to separate classes into `.class` (bootstrap) vs `.classdata` (masked) during JAR assembly.\n\n**Bootstrap inclusion criteria:**\n- `org/openjdk/btrace/core/` — core API (excluding Messages)\n- `org/openjdk/btrace/runtime/` — runtime support\n- `org/openjdk/btrace/core/extensions/` — extension API\n- `org/openjdk/btrace/libs/org/slf4j/` — relocated SLF4J (logging from bootstrap code)\n\n**Explicitly excluded from bootstrap:**\n- ASM classes (loaded via shared section)\n- JCTools queues (loaded via shared section)\n- Communication protocol classes\n- Annotation and handler classes\n\n## Build Process\n\nThe `btrace-dist/build.gradle` `btraceJar` task assembles the masked JAR:\n\n1. **`prepareAgentClassdata`**: Extracts classes from the agent shadow JAR, renames `.class` → `.classdata`, places under `META-INF/btrace/agent/`\n2. **`prepareClientClassdata`**: Same for the client shadow JAR, placed under `META-INF/btrace/client/`\n3. **`btraceJar`**: Combines bootstrap `.class` files (filtered by `btrace-bootstrap`) with the `.classdata` sections and shared classes into the final JAR\n\nShared classes (ASM, protocol, etc.) are automatically placed in `META-INF/btrace/shared/` and are accessible to both agent and client classloaders.\n\n## Debugging\n\nEnable debug output with:\n```bash\njava -Dbtrace.boot.debug=true -jar btrace.jar ...\n```\n\nThis prints classloader decisions to stderr, prefixed with `[BTrace Boot]`.\n\n## Backward Compatibility\n\nThe masked JAR coexists with the legacy multi-JAR distribution. Detection logic in `Client.java` and `RuntimeTest` checks for `btrace.jar` first and falls back to `btrace-agent.jar` if not found. The `--agent-jar` and `--boot-jar` CLI flags allow explicit path overrides for any layout.\n"
  },
  {
    "path": "docs/architecture/Version2ProtocolArchitecture.md",
    "content": "# BTrace v2 Binary Protocol Architecture\n\n**Document Version:** 1.1\n**Last Updated:** February 2026\n**Status:** Implemented (v2.3.0+)\n\n---\n\n## Table of Contents\n\n1. [Executive Summary](#executive-summary)\n2. [Problem Statement](#problem-statement)\n3. [High-Level Architecture](#high-level-architecture)\n4. [Protocol Negotiation](#protocol-negotiation)\n5. [Wire Format Specification](#wire-format-specification)\n6. [Command Conversion Layer](#command-conversion-layer)\n7. [Benefits and Trade-offs](#benefits-and-trade-offs)\n8. [Migration Path](#migration-path)\n9. [Performance Characteristics](#performance-characteristics)\n\n---\n\n## Executive Summary\n\nThe BTrace v2 binary protocol is a performance-optimized communication protocol that replaces Java Object Serialization with custom binary serialization. The v2 protocol delivers **3-6x faster** command transmission and **2-5x smaller** wire payloads while maintaining full backward compatibility with the existing v1 protocol through automatic protocol negotiation.\n\n**Key Features:**\n- Custom binary serialization (vs Java ObjectInputStream/ObjectOutputStream)\n- Automatic protocol negotiation (once per connection)\n- Compression support for large payloads (>1KB threshold)\n- Thread-safe using ReentrantLock (vs synchronized blocks)\n- Full backward compatibility with v1 protocol\n- Zero-configuration auto-detection\n\n---\n\n## Problem Statement\n\n### What Problem Does v2 Solve?\n\nThe original BTrace protocol (v1) relies on Java Object Serialization for agent-client communication. While functional, this approach has significant limitations:\n\n#### 1. Performance Bottleneck\n**Problem:** Java serialization is slow\n- ObjectInputStream/ObjectOutputStream use reflection and complex state management\n- Each command incurs serialization overhead (object graphs, metadata)\n- High CPU usage during marshaling/unmarshaling\n\n**Impact:**\n- Limits throughput for high-frequency tracing scenarios\n- Increases latency for interactive debugging\n- Consumes CPU resources that could be used for actual tracing\n\n#### 2. Large Wire Payloads\n**Problem:** Java serialization produces verbose binary format\n- Includes class metadata, type descriptors, stream headers\n- Inefficient encoding of primitive types and strings\n- No built-in compression\n\n**Impact:**\n- Increased network bandwidth usage\n- Slower transmission over slow connections\n- Higher memory usage for buffering\n\n#### 3. Language Lock-in\n**Problem:** Java serialization ties BTrace to JVM-only clients\n- Cannot implement clients in other languages (Python, Go, JavaScript)\n- Limits future extensibility (browser-based tools, IDE plugins in non-JVM languages)\n\n**Impact:**\n- Restricts ecosystem growth\n- Prevents integration with non-Java monitoring tools\n\n#### 4. Dated Concurrency Model\n**Problem:** v1 uses `synchronized` blocks for thread safety\n- Coarse-grained locking can become bottleneck\n- Limited scalability for concurrent client connections\n\n**Impact:**\n- Performance degradation with multiple concurrent clients\n- Contention under high load\n\n### Real-World Scenario\n\nConsider a production environment with high-frequency tracing:\n\n**v1 Protocol:**\n```\n10,000 MessageCommands/second\nAverage size: 512 bytes serialized\nNetwork: 5.12 MB/second\nCPU overhead: ~15% for serialization\n```\n\n**v2 Protocol:**\n```\n10,000 MessageCommands/second\nAverage size: 170 bytes serialized (3x smaller with compression)\nNetwork: 1.7 MB/second (67% reduction)\nCPU overhead: ~3% for serialization (80% reduction)\n```\n\n**Result:** 67% less bandwidth, 80% less CPU overhead, same functionality\n\n---\n\n## High-Level Architecture\n\n### Component Overview\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                        BTrace Client                             │\n│  ┌──────────────┐    ┌─────────────────┐    ┌───────────────┐  │\n│  │   Client     │───▶│ ProtocolNegotia-│───▶│  WireProtocol │  │\n│  │   (btrace-   │    │ tor (one-time)  │    │   Interface   │  │\n│  │   client)    │◀───│                 │◀───│               │  │\n│  └──────────────┘    └─────────────────┘    └───────┬───────┘  │\n│                                                      │          │\n└──────────────────────────────────────────────────────┼──────────┘\n                                                       │\n                                    ┌──────────────────┴─────────────────┐\n                                    │                                    │\n                              ┌─────▼──────┐                  ┌─────────▼──────┐\n                              │  v1 Adapter│                  │   v2 Adapter   │\n                              │  (WireIO + │                  │  (BinaryWireIO │\n                              │  ObjectI/O)│                  │  + CommandAdap-│\n                              └─────┬──────┘                  │      ter)      │\n                                    │                         └────────┬───────┘\n                                    │                                  │\n                          ┌─────────▼──────────────────────────────────▼────────┐\n                          │              TCP Socket (InputStream/                │\n                          │              OutputStream)                           │\n                          └─────────┬──────────────────────────────┬────────────┘\n                                    │                              │\n                              ┌─────▼──────┐              ┌────────▼───────┐\n                              │  v1 Adapter│              │   v2 Adapter   │\n                              │  (WireIO + │              │  (BinaryWireIO │\n                              │  ObjectI/O)│              │  + CommandAdap-│\n                              └─────┬──────┘              │      ter)      │\n                                    │                     └────────┬───────┘\n┌──────────────────────────────────┼──────────────────────────────┼──────────┐\n│                                   └──────────┬───────────────────┘          │\n│  ┌──────────────┐    ┌─────────────────┐    ▼───────────────┐              │\n│  │ RemoteClient │◀───│ ProtocolNegotia-│───▶│  WireProtocol │              │\n│  │  (btrace-    │───▶│ tor (one-time)  │    │   Interface   │              │\n│  │   agent)     │    │                 │    │               │              │\n│  └──────────────┘    └─────────────────┘    └───────────────┘              │\n│                        BTrace Agent                                         │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n### Key Components\n\n#### 1. WireProtocol Interface\n**Purpose:** Abstract wire format from business logic\n\n**Location:** `btrace-core/src/main/java/org/openjdk/btrace/core/comm/WireProtocol.java`\n\n**Responsibilities:**\n- Define contract for reading/writing Command objects\n- Abstract away serialization mechanism\n- Support protocol version introspection\n\n**Interface:**\n```java\npublic interface WireProtocol {\n    Command read(InputStream in) throws IOException;\n    void write(OutputStream out, Command cmd) throws IOException;\n    void reset() throws IOException;  // for ObjectOutputStream.reset() in v1\n    int getVersion();\n}\n```\n\n#### 2. Protocol Negotiator\n**Purpose:** Auto-detect and negotiate protocol version\n\n**Location:** `btrace-core/src/main/java/org/openjdk/btrace/core/comm/ProtocolNegotiator.java`\n\n**Responsibilities:**\n- Perform handshake at connection establishment\n- Detect client/agent protocol capabilities\n- Select optimal protocol version\n- Handle negotiation timeouts and failures\n\n#### 3. Command Adapter\n**Purpose:** Convert between v1 and v2 command representations\n\n**Location:** `btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/CommandAdapter.java`\n\n**Responsibilities:**\n- Bidirectional conversion: Command ↔ BinaryCommand\n- Preserve all command data during conversion\n- Handle type mismatches gracefully\n\n#### 4. Binary Protocol Layer\n**Purpose:** Efficient binary serialization\n\n**Location:** `btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/`\n\n**Components:**\n- **BinaryProtocol:** Low-level primitives (readInt, writeString, etc.)\n- **BinaryWireIO:** Wire format implementation (version + type + data)\n- **BinaryCommand:** Base class for all binary commands\n- **17 Command Implementations:** One per command type (Exit, Message, Instrument, etc.)\n\n---\n\n## Protocol Negotiation\n\n### Design Principle: Once Per Connection\n\n**Critical:** Protocol negotiation happens **once** when a connection is established, not per command.\n\n**Timeline:**\n```\nTime 0ms:     TCP socket established\nTime 1ms:     Client sends magic bytes (BTR2) or v1 header\nTime 5ms:     Agent responds with protocol acknowledgment\nTime 6ms:     Protocol locked for session (v1 or v2)\nTime 7ms:     First command sent (using negotiated protocol)\n...           [All subsequent commands use same protocol]\nTime 60000ms: Connection closed\n```\n\n**Why Once Per Connection:**\n- **Performance:** Negotiating per command would add massive overhead (~5ms per command)\n- **Consistency:** All commands in a session use same wire format\n- **Simplicity:** WireProtocol is set once and reused\n- **Statefulness:** Negotiated protocol stored in Client/RemoteClient instance\n\n### Handshake Protocol: Magic Byte Prefix\n\n**Approach:** Client sends 4-byte magic prefix at connection start\n\n**v2 Magic Bytes:** `0x42 0x54 0x52 0x32` (\"BTR2\" in ASCII)\n\n**Flow Diagram:**\n\n```\nClient (v2-capable)                    Agent (v2-capable)\n        │                                      │\n        ├──────── TCP Connect ────────────────▶│\n        │                                      │\n        ├──────── [0x42 0x54 0x52 0x32] ──────▶│  ◀── Client sends BTR2 magic\n        │                                      │\n        │                                      ├── Recognizes BTR2\n        │                                      ├── Agent supports v2\n        │                                      │\n        │◀─────── [0x42 0x54 0x52 0x32] ───────┤  ◀── Agent responds with BTR2\n        │                                      │\n        ├── Protocol = v2 ───────────────────  ├── Protocol = v2\n        │                                      │\n        ├──────── SetSettingsCommand (v2) ────▶│\n        ├──────── InstrumentCommand (v2) ─────▶│\n        │◀─────── StatusCommand (v2) ──────────┤\n        │◀─────── MessageCommand (v2) ─────────┤\n        ...\n```\n\n**Fallback to v1:**\n\n```\nClient (v2-capable)                    Agent (v1-only)\n        │                                      │\n        ├──────── TCP Connect ────────────────▶│\n        │                                      │\n        ├──────── [0x42 0x54 0x52 0x32] ──────▶│  ◀── Client tries v2\n        │                                      │\n        │         [5 second timeout]           ├── Does not recognize BTR2\n        │                                      ├── No response\n        │                                      │\n        ├── Timeout, fallback to v1 ───────────┤\n        │                                      │\n        ├──────── [0xAC 0xED ...] ────────────▶│  ◀── Java serialization header\n        │                                      │\n        │                                      ├── Recognizes Java serialization\n        │                                      ├── Protocol = v1\n        │                                      │\n        ├── Protocol = v1 ─────────────────────┼── Protocol = v1\n        │                                      │\n        ├──────── SetSettingsCommand (v1) ────▶│\n        ...\n```\n\n**v1-only Client:**\n\n```\nClient (v1-only)                       Agent (v2-capable)\n        │                                      │\n        ├──────── TCP Connect ────────────────▶│\n        │                                      │\n        ├──────── [0xAC 0xED ...] ────────────▶│  ◀── Java serialization header\n        │                                      │\n        │                                      ├── Detects v1 (0xAC 0xED magic)\n        │                                      ├── Protocol = v1\n        │                                      │\n        ├── Protocol = v1 ─────────────────────┼── Protocol = v1\n        │                                      │\n        ├──────── SetSettingsCommand (v1) ────▶│\n        ...\n```\n\n### Implementation Details\n\n**Agent Side (RemoteClient.getClient()):**\n```java\nSocket sock = acceptConnection();\nInputStream in = sock.getInputStream();\nOutputStream out = sock.getOutputStream();\n\n// Negotiate protocol (reads first bytes)\nProtocolVersion version = ProtocolNegotiator.negotiateAgent(in, out);\n\n// Create appropriate adapter\nWireProtocol wire = createWireProtocol(version, in, out);\n\n// Store for session\nremoteClient.setWireProtocol(wire);\n\n// All subsequent commands use 'wire'\nCommand cmd = wire.read(in);\nwire.write(out, statusResponse);\n```\n\n**Client Side (Client.submit()):**\n```java\nSocket sock = new Socket(host, port);\nInputStream in = sock.getInputStream();\nOutputStream out = sock.getOutputStream();\n\n// Negotiate protocol (sends magic bytes, waits for response)\nProtocolVersion preferred = getPreferredVersion(); // from config\nProtocolVersion version = ProtocolNegotiator.negotiateClient(in, out, preferred);\n\n// Create appropriate adapter\nWireProtocol wire = createWireProtocol(version, in, out);\n\n// Store for session\nthis.wire = wire;\n\n// All subsequent commands use 'wire'\nwire.write(out, setSettingsCmd);\nwire.write(out, instrumentCmd);\nCommand status = wire.read(in);\n```\n\n### Negotiation Timeout\n\n**Default:** 5 seconds\n\n**Rationale:**\n- Long enough for slow networks\n- Short enough to fail fast\n- Prevents hanging on unresponsive agents\n\n**Configuration:**\n```bash\n-Dbtrace.protocol.negotiation.timeout=5000\n```\n\n### Compatibility Matrix\n\n| Client Version | Agent Version | Negotiated Protocol | Notes |\n|---------------|---------------|---------------------|-------|\n| v1-only       | v1-only       | v1                  | Legacy |\n| v1-only       | v2-capable    | v1                  | Agent detects v1 magic (0xAC 0xED) |\n| v2-capable    | v1-only       | v1                  | Client timeout → fallback |\n| v2-capable    | v2-capable    | v2                  | Optimal path |\n\n**Key Insight:** Old clients always work with new agents, new clients always work with old agents\n\n---\n\n## Wire Format Specification\n\n### v2 Protocol Format\n\n**Overall Structure:**\n```\n┌──────────────┬──────────────┬────────────────────────────┐\n│ Version (1B) │ Type (1B)    │ Command Data (variable)    │\n└──────────────┴──────────────┴────────────────────────────┘\n```\n\n**Version Byte:** Current version is `0x03` (bumped from `0x02` after binary format changes to ErrorCommand and GridDataCommand)\n\n**Type Byte:** Command type identifier (0-16)\n\n| Type | Hex  | Command Name                       |\n|------|------|------------------------------------|\n| 0    | 0x00 | ERROR                              |\n| 1    | 0x01 | EVENT                              |\n| 2    | 0x02 | EXIT                               |\n| 3    | 0x03 | INSTRUMENT                         |\n| 4    | 0x04 | MESSAGE                            |\n| 5    | 0x05 | RENAME                             |\n| 6    | 0x06 | STATUS                             |\n| 7    | 0x07 | NUMBER_MAP                         |\n| 8    | 0x08 | STRING_MAP                         |\n| 9    | 0x09 | NUMBER                             |\n| 10   | 0x0A | GRID_DATA                          |\n| 11   | 0x0B | RETRANSFORMATION_START             |\n| 12   | 0x0C | RETRANSFORM_CLASS                  |\n| 13   | 0x0D | SET_PARAMS                         |\n| 14   | 0x0E | LIST_PROBES                        |\n| 15   | 0x0F | DISCONNECT                         |\n| 16   | 0x10 | RECONNECT                          |\n\n### Primitive Type Encoding\n\n**Integers (int):** 4 bytes, big-endian\n```\nValue: 42\nBytes: [0x00, 0x00, 0x00, 0x2A]\n```\n\n**Longs (long):** 8 bytes, big-endian\n```\nValue: 1234567890\nBytes: [0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xD2]\n```\n\n**Booleans (boolean):** 1 byte\n```\ntrue:  [0x01]\nfalse: [0x00]\n```\n\n**Strings (String):** Length-prefixed UTF-8\n```\nFormat: [length (4B)] [UTF-8 bytes]\n\nExample: \"Hello\"\nBytes: [0x00, 0x00, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F]\n        └─── length=5 ────┘  └────── \"Hello\" UTF-8 ──────────┘\n```\n\n**Null Strings:** Length = -1\n```\nnull: [0xFF, 0xFF, 0xFF, 0xFF]\n```\n\n**Byte Arrays (byte[]):** Length-prefixed raw bytes\n```\nFormat: [length (4B)] [raw bytes]\n\nExample: [0xCA, 0xFE, 0xBA, 0xBE]\nBytes: [0x00, 0x00, 0x00, 0x04, 0xCA, 0xFE, 0xBA, 0xBE]\n        └─── length=4 ────┘  └──── raw bytes ────┘\n```\n\n### Example: MessageCommand\n\n**Structure:**\n```\n┌─────────┬─────────┬──────────────┬─────────────────┬─────────────────┐\n│ Version │ Type    │ Urgent Flag  │ Timestamp (8B)  │ Message (String)│\n│ (1B)    │ (1B)    │ (1B)         │                 │                 │\n└─────────┴─────────┴──────────────┴─────────────────┴─────────────────┘\n  0x02      0x04      0x00/0x01      long              length + UTF-8\n```\n\n**Example Bytes:**\n```\nMessage: \"BTrace started\"\nTimestamp: 1638360000000\nUrgent: false\n\nHex dump:\n02 04 00 00 00 00 01 7D 28 4F 2D 00 00 00 00 0E\n42 54 72 61 63 65 20 73 74 61 72 74 65 64\n\nBreakdown:\n02           - Version = 2\n04           - Type = MESSAGE (4)\n00           - Urgent = false\n00 00 00 01 7D 28 4F 2D - Timestamp = 1638360000000\n00 00 00 0E  - String length = 14\n42 54 72 61 63 65 20 73 74 61 72 74 65 64 - \"BTrace started\" (UTF-8)\n```\n\n### Compression\n\n**Trigger:** Message size > 1024 bytes (configurable)\n\n**Algorithm:** Java Deflater/Inflater (BEST_SPEED)\n\n**Format with Compression:**\n```\n┌─────────┬─────────┬──────────────┬──────────────────┬────────────────────┐\n│ Version │ Type    │ Urgent Flag  │ Compressed Flag  │ Compressed/Raw Data│\n│ (1B)    │ (1B)    │ (1B)         │ (1B)             │                    │\n└─────────┴─────────┴──────────────┴──────────────────┴────────────────────┘\n  0x02      0x04      0x00/0x01      0x00/0x01          byte array\n```\n\n**Compressed Data:**\n```\n[Original Length (4B)] [Compressed Length (4B)] [Deflated Bytes]\n```\n\n**Benefits:**\n- 3-5x size reduction for large text messages\n- Automatically applied for messages >1KB\n- Transparent to Command layer\n\n---\n\n## Command Conversion Layer\n\n### Purpose\n\nThe **CommandAdapter** provides bidirectional conversion between v1 (`Command`) and v2 (`BinaryCommand`) representations, enabling:\n\n1. v2 wire protocol to work with v1 business logic\n2. Gradual migration without rewriting all command handling\n3. Testing v2 implementation against v1 baseline\n\n### Architecture\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                      Command Processing                          │\n│  ┌──────────────┐                             ┌──────────────┐  │\n│  │ BTrace Agent │                             │ BTrace Client│  │\n│  │   (v1 API)   │                             │   (v1 API)   │  │\n│  └──────┬───────┘                             └───────┬──────┘  │\n│         │                                             │          │\n│         │ Command                            Command │          │\n│         ▼                                             ▼          │\n│  ┌──────────────────────────────────────────────────────────┐  │\n│  │              CommandAdapter (conversion)                 │  │\n│  │   toBtraceCommand()        ↔      toBinaryCommand()      │  │\n│  └──────┬───────────────────────────────────────────┬───────┘  │\n│         │                                            │          │\n│         │ BinaryCommand                 BinaryCommand│          │\n│         ▼                                            ▼          │\n│  ┌──────────────────┐                        ┌──────────────┐  │\n│  │  BinaryWireIO    │                        │  BinaryWireIO│  │\n│  │    (write)       │                        │    (read)    │  │\n│  └──────┬───────────┘                        └───────┬──────┘  │\n│         │                                            │          │\n└─────────┼────────────────────────────────────────────┼──────────┘\n          │                                            │\n          ▼                                            ▼\n    [Wire Bytes]  ─────────────────────────────▶  [Wire Bytes]\n```\n\n### Conversion Examples\n\n**v1 → v2 (Client sending command):**\n```java\n// Client has Command object (v1)\nMessageCommand v1Cmd = new MessageCommand(\"Hello from BTrace\");\n\n// Convert to BinaryCommand (v2)\nBinaryCommand v2Cmd = CommandAdapter.toBinaryCommand(v1Cmd);\n// Result: BinaryMessageCommand with message=\"Hello from BTrace\"\n\n// Serialize to wire\nBinaryWireIO.write(outputStream, v2Cmd);\n// Wire: [0x02][0x04][urgent][timestamp][length][UTF-8 bytes]\n```\n\n**v2 → v1 (Agent receiving command):**\n```java\n// Read from wire\nBinaryCommand v2Cmd = BinaryWireIO.read(inputStream);\n// Result: BinaryMessageCommand\n\n// Convert to Command (v1)\nCommand v1Cmd = CommandAdapter.toBtraceCommand(v2Cmd);\n// Result: MessageCommand with same data\n\n// Pass to v1 business logic\nagent.onCommand(v1Cmd);\n```\n\n### Data Fidelity\n\n**Guarantee:** All data is preserved during conversion\n\n**Special Cases:**\n\n1. **ErrorCommand:**\n   - v1: Contains full `Throwable` object (type + message + stack trace)\n   - v2: Contains exception class name, message, and stack trace as strings\n   - **Conversion:** Adapter extracts exception class, message, and stack trace from the `Throwable`; on deserialization, wraps them in a `RemoteException` that preserves the original type and trace\n\n2. **GridDataCommand:**\n   - v1: Object[][] (mixed types), optional column names\n   - v2: Typed cells (String, Integer, Long, Float, Double, Boolean, HistogramData, null), column names preserved\n   - **Conversion:** Type preservation via explicit type codes; `HistogramData` has a dedicated encoding\n\n3. **NumberMapDataCommand:**\n   - v1: `Map<String, Number>` (can carry any `Number` subclass)\n   - v2: Typed encoding for int/long/float/double plus dedicated codes for `BigInteger` and `BigDecimal`\n   - **Conversion:** Preserves precision for all standard `Number` types\n\n4. **StatusCommand:**\n   - v1: Single int (positive=success, negative=failure)\n   - v2: flag (int) + success (boolean)\n   - **Conversion:** `flag = abs(v1), success = (v1 > 0)`\n\n### WireProtocol Adapters\n\n**WireIOV1Adapter:**\n```java\npublic class WireIOV1Adapter implements WireProtocol {\n    private ObjectInputStream ois;\n    private ObjectOutputStream oos;\n\n    public Command read(InputStream in) throws IOException {\n        return WireIO.read(ois);  // Uses v1 protocol\n    }\n\n    public void write(OutputStream out, Command cmd) throws IOException {\n        WireIO.write(oos, cmd);  // Uses v1 protocol\n    }\n\n    public void reset() throws IOException {\n        oos.reset();  // ObjectOutputStream state management\n    }\n}\n```\n\n**WireIOV2Adapter:**\n```java\npublic class WireIOV2Adapter implements WireProtocol {\n    private InputStream in;\n    private OutputStream out;\n\n    public Command read(InputStream in) throws IOException {\n        BinaryCommand binaryCmd = BinaryWireIO.read(in);\n        return CommandAdapter.toBtraceCommand(binaryCmd);  // Convert v2→v1\n    }\n\n    public void write(OutputStream out, Command cmd) throws IOException {\n        BinaryCommand binaryCmd = CommandAdapter.toBinaryCommand(cmd);  // Convert v1→v2\n        BinaryWireIO.write(out, binaryCmd);\n    }\n\n    public void reset() throws IOException {\n        // No-op: v2 has no state to reset\n    }\n}\n```\n\n---\n\n## Benefits and Trade-offs\n\n### Benefits\n\n#### 1. Performance: 3-6x Faster\n**Measurement:** 10,000 iterations, InstrumentCommand (100KB bytecode)\n\n| Metric | v1 (Java Serialization) | v2 (Binary) | Improvement |\n|--------|------------------------|-------------|-------------|\n| Serialize | 450ms | 90ms | **5x faster** |\n| Deserialize | 520ms | 110ms | **4.7x faster** |\n| Round-trip | 970ms | 200ms | **4.85x faster** |\n\n**Why:**\n- No reflection overhead\n- Minimal object allocation\n- Direct byte manipulation\n- Optimized for BTrace command patterns\n\n#### 2. Size: 2-5x Smaller\n**Measurement:** Wire size comparison\n\n| Command Type | v1 Size | v2 Size | Reduction |\n|-------------|---------|---------|-----------|\n| ExitCommand | 45 bytes | 15 bytes | **3x smaller** |\n| MessageCommand (small) | 180 bytes | 60 bytes | **3x smaller** |\n| MessageCommand (large, 10KB) | 10,240 bytes | 2,150 bytes | **4.8x smaller** (compressed) |\n| InstrumentCommand (100KB) | 102,400 bytes | 34,100 bytes | **3x smaller** (compressed) |\n\n**Why:**\n- No Java serialization metadata\n- Efficient primitive encoding\n- Automatic compression for large payloads\n- Minimal framing overhead\n\n#### 3. Thread Safety: ReentrantLock\n**v1:** `synchronized (ObjectOutputStream)`\n**v2:** `ReentrantLock` in BinaryWireIO\n\n**Benefits:**\n- Better scalability under contention\n- Fairness guarantees (optional)\n- Interruptible locking\n- Try-lock with timeout\n\n#### 4. Language Independence\n**v1:** Requires Java client (ObjectInputStream/ObjectOutputStream)\n**v2:** Simple binary format, can be implemented in any language\n\n**Future possibilities:**\n- Python BTrace client\n- Go monitoring tools\n- JavaScript browser-based debugger\n- VS Code extension in TypeScript\n\n#### 5. Backward Compatibility\n**Zero breaking changes:** Old clients work with new agents, new clients work with old agents\n\n**Migration path:** Automatic, no user action required\n\n### Trade-offs\n\n#### 1. Code Complexity\n**Added:** Protocol negotiation, WireProtocol abstraction, CommandAdapter\n**Mitigated by:** Clean interfaces, comprehensive tests\n\n#### 2. Negotiation Latency\n**Cost:** ~5-10ms per connection establishment\n**Amortized over:** Entire session (thousands of commands)\n**Net impact:** Negligible\n\n#### 3. Compression CPU Overhead\n**Cost:** Deflate/Inflate CPU usage for large messages\n**Threshold:** Only for messages >1KB\n**Net benefit:** Reduced network I/O usually more expensive than compression\n\n#### 4. Testing Burden\n**Requirement:** Test v1, v2, and mixed scenarios\n**Mitigated by:** Automated test matrix, reusable test harness\n\n### When to Use v2\n\n**Recommended for:**\n- High-frequency tracing (>100 commands/second)\n- Large instrumentation payloads\n- Remote tracing over slow networks\n- Production environments with multiple agents\n\n**v1 sufficient for:**\n- Interactive debugging (low frequency)\n- Local tracing (no network)\n- Legacy environments (no upgrade path)\n\n---\n\n## Migration Path\n\n### For End Users (Transparent)\n\n**No action required:** Protocol negotiation is automatic\n\n**Optional configuration:**\n```bash\n# Force v2 (fail if agent doesn't support it)\n-Dbtrace.protocol.version=2\n\n# Force v1 (for testing or compatibility)\n-Dbtrace.protocol.version=1\n\n# Auto-detect (default)\n-Dbtrace.protocol.version=auto\n```\n\n### For Developers\n\n#### Completed\n- All 17 command types implemented and tested\n- Protocol negotiation implemented\n- RemoteClient and Client refactored with WireProtocol abstraction\n- Backward compatibility verified (v1 clients work with v2 agents and vice versa)\n- Default to v2 with automatic fallback to v1\n\n#### Post-Release Technical Debt\n- Add v2-only end-to-end integration test suite\n- Stress tests under sustained high-frequency tracing\n\n### Rollback Plan\n\n**If issues arise:**\n1. Disable v2 by default: `-Dbtrace.protocol.version=1`\n2. Roll back agent/client to previous version\n3. Fix issues, re-test\n4. Re-enable v2\n\n**Safety:** v1 protocol remains fully functional, no risk of data loss\n\n---\n\n## Performance Characteristics\n\n### Throughput\n\n**Scenario:** Single client, continuous command stream\n\n| Command Type | v1 (cmds/sec) | v2 (cmds/sec) | Improvement |\n|--------------|---------------|---------------|-------------|\n| ExitCommand | 120,000 | 550,000 | **4.6x** |\n| MessageCommand (small) | 45,000 | 180,000 | **4x** |\n| MessageCommand (large) | 2,500 | 12,000 | **4.8x** |\n| InstrumentCommand | 800 | 3,500 | **4.4x** |\n| GridDataCommand | 8,000 | 32,000 | **4x** |\n\n**Bottleneck (v1):** Java serialization overhead\n**Bottleneck (v2):** Network I/O (achieved wire-speed)\n\n### Latency\n\n**Scenario:** Round-trip time (client send → agent receive → process → respond → client receive)\n\n| Command Type | v1 p50 | v1 p99 | v2 p50 | v2 p99 | Improvement |\n|--------------|--------|--------|--------|--------|-------------|\n| ExitCommand | 1.2ms | 3.5ms | 0.3ms | 0.8ms | **4x faster** |\n| MessageCommand | 2.8ms | 8.1ms | 0.7ms | 2.1ms | **4x faster** |\n| InstrumentCommand | 45ms | 120ms | 12ms | 35ms | **3.75x faster** |\n\n**Key insight:** v2 reduces tail latency significantly (p99)\n\n### Memory\n\n**Scenario:** Memory allocations per command\n\n| Command Type | v1 Allocations | v2 Allocations | Reduction |\n|--------------|----------------|----------------|-----------|\n| ExitCommand | 850 bytes | 120 bytes | **7x less** |\n| MessageCommand | 2.1 KB | 450 bytes | **4.7x less** |\n| InstrumentCommand | 125 KB | 102 KB | **1.2x less** (bytecode dominates) |\n\n**GC impact:** Fewer allocations → less GC pressure → smoother performance\n\n### Network Bandwidth\n\n**Scenario:** 10,000 MessageCommands (average 500 bytes text)\n\n| Protocol | Wire Size | Network Usage |\n|----------|-----------|---------------|\n| v1 | 8.2 MB | 100% baseline |\n| v2 (no compression) | 5.1 MB | 62% |\n| v2 (with compression) | 1.9 MB | 23% |\n\n**Benefit:** 77% bandwidth reduction with compression\n\n---\n\n## Conclusion\n\nThe BTrace v2 binary protocol delivers significant performance improvements (3-6x faster, 2-5x smaller) while maintaining full backward compatibility through automatic protocol negotiation. The architecture is clean, well-tested, and production-ready.\n\n**Key Takeaways:**\n- Protocol negotiation happens once per connection (not per command)\n- Automatic fallback ensures zero breaking changes\n- Performance gains are substantial and validated by benchmarks\n- Migration is transparent to end users\n\n**Implementation status:**\n- Protocol version bumped to 3 after binary format changes\n- All 17 command types covered by unit tests (26+ tests)\n- ErrorCommand preserves exception class, message, and stack trace via RemoteException\n- GridDataCommand preserves HistogramData and column names\n- NumberMapDataCommand preserves BigInteger and BigDecimal\n\n---\n\n## References\n\n- Implementation: `btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/`\n- Tests: `btrace-core/src/test/java/org/openjdk/btrace/core/comm/v2/`\n- README: `btrace-core/src/main/java/org/openjdk/btrace/core/comm/v2/Readme.md`\n"
  },
  {
    "path": "docs/plans/2026-04-20-NEXT-SESSION-PLAN.md",
    "content": "# Next Session Plan - Complete MethodHandle-Level Guard Implementation\n\n## Current State (Session 3 end)\n- Identified root cause: `$btrace$$level` field never initialized, so bytecode level checks always fail\n- Designed superior solution: Move level checking to MethodHandle linking layer\n- Implemented framework in `HandlerRepositoryImpl`:\n  - `applyLevelGuard()` method exists and is called\n  - `createLevelCheckMH()` stub (currently returns constant true)\n  - `createNoopMH()` fully implemented\n  - Uses `MethodHandles.guardWithTest()` composition\n- Commits done:\n  - f3780e60: refactor(instr): move level checking to MethodHandle linking layer\n  - c5729200: docs: architectural refinement - level checking at MethodHandle layer\n\n## What Needs To Be Done\n\n### 1. DISABLE BYTECODE-LEVEL LEVEL CHECKS (File: MethodTrackingContext.java)\nThe bytecode currently generates level checks like:\n```\ngetstatic $btrace$$level\nldc 100\nif_icmplt skip_handler\ninvokedynamic\nskip_handler:\n```\n\nThis prevents INVOKEDYNAMIC from executing when level=0.\n\n**Location**: `/Users/jbachorik/src/btrace/btrace-instr/src/main/java/org/openjdk/btrace/instr/MethodTrackingContext.java`\n- Find method `addLevelChecks(Supplier<Label> action)` around line 245-290\n- Replace the entire level checking logic with simple passthrough:\n  ```java\n  private Label addLevelChecks(Supplier<Label> action) {\n    OnMethod om = invocation.getOnMethod();\n    // Level checks are now in MethodHandle layer (HandlerRepositoryImpl.applyLevelGuard)\n    return action.get();\n  }\n  ```\n- This disables bytecode-level checks; MethodHandle layer takes over\n\n### 2. IMPLEMENT REAL LEVEL CHECK IN createLevelCheckMH() (File: HandlerRepositoryImpl.java)\n**Location**: Line ~90 in HandlerRepositoryImpl.java\n\nCurrent stub returns constant true. Needs to:\n1. Create a MethodHandle that queries BTraceRuntime for current instrumentation level\n2. Compare against the Level requirement from the OnMethod annotation\n3. Return boolean result matching the handler's parameter types\n\n**Implementation approach**:\n```java\nprivate static MethodHandle createLevelCheckMH(Level level, MethodType testType) throws Throwable {\n  // Get the Interval from the level (e.g., \">=100\")\n  Interval interval = level.getValue();\n  \n  // Create MH that queries current instrumentation level from BTraceRuntime\n  // This needs to be done via reflection since we're in the agent module\n  // and BTraceRuntime lives in the runtime module\n  MethodHandle getLevelMH = ... // get current level from runtime\n  \n  // Create comparison logic based on interval (>=, <=, ==, etc.)\n  MethodHandle compareLevel = ... // compare current level against interval\n  \n  // Drop arguments to match testType (same params, return boolean)\n  return MethodHandles.dropArguments(compareLevel, 0, testType.parameterArray());\n}\n```\n\n**Key challenge**: Need to query current instrumentation level. Options:\n- Call static method on BTraceRuntime to get current level\n- Store level in a ThreadLocal accessible from handler resolution\n- Pass level through probe metadata\n\n### 3. REMOVE $btrace$$level FIELD FROM PROBE CLASS\nOnce bytecode-level checks are disabled, the `$btrace$$level` field is no longer needed.\n\n**Location**: `/Users/jbachorik/src/btrace/btrace-instr/src/main/java/org/openjdk/btrace/instr/Preprocessor.java`\n- Find method `addLevelField(ClassNode cn)` around line 521\n- Either comment it out or make it conditional on a feature flag\n\nThis simplifies the probe class bytecode significantly.\n\n### 4. TEST THE COMPLETE SOLUTION\n```bash\n# Build\n./gradlew build -x test\n\n# Run failing test\nsource ~/.sdkman/bin/sdkman-init.sh\nJAVA_TEST_HOME=$(sdk home java 11.0.23-tem) ./gradlew :integration-tests:test \\\n    --tests 'tests.BTraceFunctionalTests.testOnMethodLevel' -Pintegration\n```\n\n**Expected result**: Test passes with output containing:\n- \"[this, noargs]\"\n- \"[this, args]\"\n- \"{xxx}\"\n\n## Architecture Summary (What We're Building)\n\n**Old approach (BROKEN)**:\n```\nInstrumented bytecode checks: if (probeClass.$btrace$$level >= 100) { invokedynamic }\n└─ Problem: Field never initialized, always 0, condition always false\n```\n\n**New approach (BEING IMPLEMENTED)**:\n```\n1. Instrumented bytecode: invokedynamic (no level check)\n   └─ Calls IndyDispatcher.bootstrap()\n\n2. IndyDispatcher.bootstrap() \n   └─ Calls HandlerRepositoryImpl.resolveHandler()\n\n3. HandlerRepositoryImpl.resolveHandler()\n   └─ Resolves handler MethodHandle\n   └─ Calls applyLevelGuard() to wrap with level check\n   └─ Returns composed MH: guardWithTest(levelCheck, realHandler, noop)\n\n4. guardWithTest composition\n   └─ At runtime: levelTest() returns boolean\n   └─ If true: invoke realHandler\n   └─ If false: invoke noop (return default value)\n```\n\n**Benefits**:\n- No runtime field initialization needed\n- JIT can optimize knowing level at compile time\n- No deopt avalanche when level changes (MutableCallSite relinks)\n- Clean separation: linking-time policy, not bytecode policy\n\n## Files Modified So Far\n- HandlerRepositoryImpl.java: Added applyLevelGuard(), createLevelCheckMH(), createNoopMH()\n- RESUME.md: Updated with architectural refinement\n\n## Files To Modify Next Session\n1. MethodTrackingContext.java: Disable bytecode-level checks\n2. HandlerRepositoryImpl.java: Implement createLevelCheckMH() with real logic\n3. Preprocessor.java: Remove/disable addLevelField()\n4. Test and verify\n\n## Command to Pick Up\n```bash\ncd /Users/jbachorik/src/btrace\ngit log --oneline -5  # Should show the recent commits\ngit status  # Should be clean\n```\n\n## Critical Insight (From User)\nThe user identified that level checks should happen at MethodHandle linking time, not in bytecode. This is architecturally superior because:\n- Avoids initializing runtime fields in probe class\n- Prevents deopt avalanche\n- Allows JIT to optimize based on known levels\n- Cleaner separation of concerns\n\nThis insight completely changed the approach from \"fix the initialization\" to \"eliminate the field and check at linking time\".\n"
  },
  {
    "path": "docs/plans/2026-04-20-probe-class-unloading-RESUME.md",
    "content": "# Session resume — probe-class-unloading work (PR #830)\n\n**Last updated:** 2026-04-20\n**Branch:** `phase3-invokedynamic-dispatch` @ `73c3422d` (pushed) + 1 uncommitted WIP on `Client.java`\n**Remote:** `origin/phase3-invokedynamic-dispatch`\n**PR:** https://github.com/btraceio/btrace/pull/830\n\n## Current Session Finding\n\n**Investigation revealed:** Test failure root cause is NOT the race condition that `synchronized loadClass` was supposed to fix. Bisection shows the test started failing at commit **906d924d** (per-probe ClassLoader/hidden class definition), not at ec451089 (removeRuntime wire-up). \n\nThe test failure signature is: probe loads successfully (\"Successfully started BTrace probe\") but the traced app produces zero output from probe methods. This indicates the per-probe ClassLoader change broke probe method invocation or output capture, not probe loading itself.\n\n**Next session must focus on:** Diagnosing why probe methods don't execute or don't produce output after the per-probe ClassLoader change. The synchronized loadClass is a valid improvement to prevent the race (and prevents NPE crashes), but doesn't fix the root test failure.\n\n## Status\n\n**Committed + pushed:**\n- `07842ea8` perf(instr): key handler cache by composite HandlerKey, not concatenated string\n- `27dae4ac` feat(instr): expose defined probe Class<?> on BTraceProbe\n- `b3501afe` refactor(instr): resolve probe handler via probe.getProbeClass(), not Class.forName\n- `906d924d` feat(runtime): define probes in per-probe ClassLoader / hidden class (JDK 8, 9-14, 15+)\n- `76fd6a28` refactor(runtime): shared ProbeAnchor helper, drop mustBeBootstrap, add BTraceRuntimes.removeRuntime\n- `1054b463` test(instr): add same-name re-definition test; docs: correct probe-residency javadoc\n- `ec451089` fix(agent): unregister BTraceRuntime on probe detach to prevent leak\n- `73c3422d` refactor(instr): move handler MethodHandle cache to per-probe instance\n\n**Unit tests (`:btrace-instr:test`): green on both JDK 8 and JDK 21.**\n\n**CI failures on PR #830** (`gh pr checks 830`):\n- `test (11.0.30-tem)` FAIL: `testJfr`, `testOnMethodLevel`, `testAttachWithMaskedJar`\n- `test (8.0.482-tem)` FAIL: `testOnMethodLevel`, `testAttachWithMaskedJar`\n- JDK 17/21/25/26 jobs were pending at last check\n\n## Root cause identified\n\n**Race between `Client.loadClass` (Thread-0, probe load) and `Client.onExit` (Thread-1, detach) introduced by `ec451089`.**\n\nBefore `ec451089`:\n- `Client.cleanupTransformers()` did not touch `BTraceRuntimeAccessImpl.runtimes` map.\n- Race between load and onExit was benign (map stayed populated).\n\nAfter `ec451089`:\n- `cleanupTransformers` calls `BTraceRuntimes.removeRuntime(probe.getClassName())` which does `runtimes.remove(className)`.\n- If Thread-1 fires before Thread-0 finishes `probe.register()` → `defineClass` → probe class `<clinit>` (which calls `BTraceRuntimeAccess.forClass(probe.class)` → `runtimes.get(cl.getName())`), the map is empty, `runtime.init(...)` NPEs.\n\nThe probe's command-listener thread (Thread-1) is **started from inside the probe's `<clinit>`** (via `BTraceRuntimeImplBase.init()`), so it can receive an `ExitCommand` off the wire before `<clinit>` finishes running on Thread-0.\n\n### Debug trace (key evidence)\n\nCaptured on `JAVA_TEST_HOME=$(sdk home java 11.0.23-tem) ./gradlew :integration-tests:test --tests tests.BTraceFunctionalTests.testOnMethodLevel -Pintegration`:\n\n```\n[traced app] [DEBUG-addRuntime] key=org.openjdk.btrace.runtime.auxiliary.OnMethodLevelTest runtimes@... accessClass@... via=org.openjdk.btrace.boot.MaskedClassLoader@...\n[traced app] [DEBUG-addRuntime] after put, size=1 keys=[org.openjdk.btrace.runtime.auxiliary.OnMethodLevelTest]\n[traced app] [Thread-0] DEBUG org.openjdk.btrace.instr.BTraceProbeSupport - about to defineClass org.openjdk.btrace.runtime.auxiliary.OnMethodLevelTest\n[traced app] [Thread-1] DEBUG org.openjdk.btrace.agent.Client - onExit:\n[traced app] [DEBUG-forClass] cl.getName()=... keys=[]   ← map cleared by Thread-1 before <clinit> read it\n[traced app] [DEBUG-removeRuntime] caller: Client.cleanupTransformers(Client.java:520)\n[traced app] java.lang.ExceptionInInitializerError\n[traced app]   at ...BTraceRuntimeImpl_11.defineClass(BTraceRuntimeImpl_11.java:246)   ← clz.getConstructor().newInstance()\n[traced app]   at ...BTraceProbeSupport.defineClass(BTraceProbeSupport.java:311)\n[traced app]   at ...BTraceProbePersisted.register(BTraceProbePersisted.java:567)\n[traced app]   at ...Client.loadClass(Client.java:425)\n[traced app]   at ...RemoteClient.<init>(RemoteClient.java:194)\n[traced app] Caused by: java.lang.NullPointerException\n[traced app]   at ...BTraceRuntimeAccessImpl.forClassInternal(BTraceRuntimeAccessImpl.java:192)   ← runtime = runtimes.get(cl.getName()); runtime.init(...)\n```\n\nConfirmed `runtimes@<id>` and `accessClass@<id>` are identical between `addRuntime` and `forClassInternal` — same static map, same agent-CL `BTraceRuntimeAccessImpl` class. Classloader concerns ruled out. Pure thread race.\n\n## Fix attempt in progress (UNCOMMITTED)\n\nAdded `synchronized` modifier to `Client.loadClass` in `btrace-agent/src/main/java/org/openjdk/btrace/agent/Client.java:330`:\n\n```diff\n- final Class<?> loadClass(InstrumentCommand instr) throws IOException {\n+ final synchronized Class<?> loadClass(InstrumentCommand instr) throws IOException {\n```\n\nRationale: `onExit` is already `synchronized void onExit(int exitCode)` on the same `this` monitor (Client.java:293). Making loadClass synchronized forces mutual exclusion so `onExit` waits for `loadClass` to finish before running `cleanupTransformers`.\n\n**Status when session interrupted:** the edit landed (verified via grep). A test run was about to start to confirm the fix but was interrupted. The one earlier test run after this edit still showed Thread-1 proceeding while Thread-0 was in defineClass, which contradicts the synchronization. Possible explanations to investigate on resume:\n1. The test was run against a stale build (Gradle cache issue). Re-check with a clean build.\n2. `loadClass` is being called somewhere that bypasses the synchronized method dispatch (unlikely — Java resolves synchronized via method descriptor).\n3. `onExit` was entered BEFORE `loadClass` acquired the lock — i.e., Thread-1 got the lock first, released it (because no probe yet, onExit no-ops), and by the time Thread-0 runs loadClass, the map is empty. Need to check whether an early onExit can fire before any loadClass.\n\n## Known-to-fail tests (local reproduction)\n\n```bash\nsource ~/.sdkman/bin/sdkman-init.sh\nJAVA_TEST_HOME=$(sdk home java 11.0.23-tem) ./gradlew :integration-tests:test \\\n    --tests 'tests.BTraceFunctionalTests.testOnMethodLevel' -Pintegration\n```\n\nWith `BTRACE_TEST_DEBUG=true` set, you get the full `[traced app] [btrace out] [traced app]` dump including probe `<clinit>` stack traces.\n\nAlso failing: `tests.BTraceFunctionalTests.testJfr` (JDK 11 only), `tests.JBangAttachDockerTest.testAttachWithMaskedJar` (both). The JBang one failed on CI but local run skips it if Docker isn't running.\n\n## Root Cause Analysis (Per-Probe ClassLoader Issue)\n\nThe per-probe ClassLoader change (906d924d) creates each probe in a fresh unnamed ClassLoader. Initial hypothesis was ClassLoader visibility issue (probe can't see BTraceUtils).\n\n**Attempt 1 - Add app ClassLoader as parent**: Updated all BTraceRuntimeImpl versions to pass app ClassLoader as parent to per-probe ClassLoader. **Result: FAILED**. Tests still fail with zero output from probes.\n\n**Revised hypothesis**: The issue is NOT ClassLoader visibility but something deeper:\n- Probes load successfully (\"Successfully started BTrace probe\" appears)\n- But traced app produces ZERO output, not different output\n- This suggests the instrumented bytecode in traced app is not invoking the probe at all\n- Likely cause: INVOKEDYNAMIC dispatch or handler resolution broken when probe is in isolated CL\n\n**Evidence**:\n- Test passes on 07842ea8 with full probe output: `[btrace out] none [this, noargs]`\n- Test fails on 906d924d with zero output from probes\n- ClassLoader parent fix didn't help, ruling out visibility as root cause\n- Handler cache refactoring (73c3422d) is still suspect - needs investigation\n\n## Session 2 Work Summary\n\n**Investigation & Attempts:**\n1. Added `synchronized` to `Client.loadClass` to prevent race condition (valid fix but doesn't solve test failure)\n2. Used git bisection to identify 906d924d (per-probe ClassLoader) as breaking change\n3. Hypothesized ClassLoader visibility issue (per-probe CL can't see BTraceUtils)\n4. **Fix Attempt**: Pass app ClassLoader as parent to per-probe ClassLoader\n   - Modified ProbeAnchor.defineAnchor() to accept parent parameter\n   - Updated BTraceRuntimeImpl_8/9/11 to pass app CL as parent\n   - **Result**: FAILED - tests still produce zero output from probes\n   - **Conclusion**: Visibility is NOT the root cause\n\n**Revised diagnosis**: Issue is INVOKEDYNAMIC dispatch or handler resolution failure when probe in isolated CL.\n\n## Session 3 Work Summary - REFINED DIAGNOSIS\n\n**CORRECTED: Methods ARE present in instrumented bytecode**\n\nInitial analysis was incorrect - when using javap with full disassembly (`-c -private`), callA() and callB() ARE present in the instrumented bytecode with proper INVOKEDYNAMIC instructions.\n\n**What we found:**\n- Instrumented Main.class HAS callA() and callB() methods\n- Both methods contain conditional INVOKEDYNAMIC instructions that invoke probe handlers\n- The INVOKEDYNAMIC is guarded by: `if (LinkingFlag.get() != 0) skip invokedynamic`\n- INVOKEDYNAMIC is inserted at correct locations in the method bodies\n\n**CRITICAL ROOT CAUSE IDENTIFIED:**\n- The `$btrace$$level` static field in the probe class is initialized to 0\n- Instrumented code checks: `if (probeClass.$btrace$$level >= 100) { invokedynamic }`\n- Since level is 0 and the check requires >= 100, the condition is ALWAYS FALSE\n- Therefore INVOKEDYNAMIC is never executed, bootstrap is never called, handlers never run\n- The field is never updated to the correct level value (100, 150) from @Level annotations\n\nThis explains:\n- Why INVOKEDYNAMIC instruction exists in bytecode but isn't executed\n- Why IndyDispatcher.bootstrap() is never called\n- Why probe handlers produce zero output\n- Why tests are failing on all JDK versions\n\n**The issue is NOT related to per-probe ClassLoaders** - it's a probe-level initialization problem that existed before or was introduced by recent changes.\n\n## ARCHITECTURAL REFINEMENT - MOVE LEVEL CHECKING TO METH HANDLE LAYER\n\n**Better design: Level checking should happen during INVOKEDYNAMIC linking, not in bytecode**\n\nThe root cause is clear: `$btrace$$level` field stays at 0 because it's never initialized. But instead of fixing the initialization, move the level check to where it belongs - the MethodHandle linking layer.\n\n### New approach (f3780e60):\n\n1. **Remove bytecode-level level check**\n   - No need to initialize `$btrace$$level` in probe class\n   - Delete the level guard from instrumented methods\n\n2. **Implement level checking in `HandlerRepositoryImpl.applyLevelGuard()`**\n   - Called during INVOKEDYNAMIC bootstrap (handler resolution)\n   - Extracts level from OnMethod metadata\n   - Composes handler with level guard using MethodHandles.guardWithTest()\n\n3. **Benefits of this approach**\n   - No runtime initialization of probe class fields\n   - JIT can optimize based on known level value\n   - Prevents deopt avalanche when level changes\n   - Cleaner separation of concerns\n\n### Next session completion:\n\n1. **Implement MethodHandle.guardWithTest composition**\n   ```java\n   MethodHandle levelCheck = createLevelTestMH(level.getValue());\n   return MethodHandles.guardWithTest(levelCheck, realHandler, noop());\n   ```\n\n2. **Remove level checks from instrumented bytecode**\n   - Delete the conditional INVOKEDYNAMIC guard in Assembler/MethodTrackingContext\n   - This simplifies probe bytecode significantly\n\n3. **Create runtime level query MethodHandle**\n   - Hook into BTraceRuntime to query current instrumentation level\n   - Return boolean that can be used in guardWithTest\n\n4. **Verify the fix**\n   - Tests should pass with proper level-guarded handlers\n   - No need for any probe class field modifications\n\n3. **Verify no leftover debug code** in BTraceRuntimeAccessImpl.java (already confirmed clean).\n\n2. **Re-run the failing integration test** after the `synchronized loadClass` edit to confirm or refute the fix:\n   ```\n   source ~/.sdkman/bin/sdkman-init.sh\n   JAVA_TEST_HOME=$(sdk home java 11.0.23-tem) ./gradlew :integration-tests:test \\\n       --tests 'tests.BTraceFunctionalTests.testOnMethodLevel' -Pintegration\n   ```\n   Expected on success: PASS. If still fails, likely cause: `onExit` was entered before `loadClass` because of out-of-order command delivery on the wire.\n\n3. **If synchronized fix doesn't work**, fall back to a state-flag approach:\n   - Add `private volatile boolean probeLoaded = false;` to `Client`.\n   - Set true at the end of `loadClass` inside the try block, AFTER `probe.register()` returns successfully.\n   - In `cleanupTransformers()`, only call `BTraceRuntimes.removeRuntime(probeName)` if `probeLoaded` is true.\n   - Accept the trade-off: if load fails before the flag is set, we leak one runtime entry — but a failed load is exceptional and a crash on a normal detach is far worse.\n\n4. **Also investigate `testJfr` and `testAttachWithMaskedJar`** — may or may not share the same root cause. Look at their stack traces on CI via `gh api repos/btraceio/btrace/actions/jobs/72048627587/logs` (JDK 11) and `.../72048627596/logs` (JDK 8).\n\n5. **Full verification** once fix is in place:\n   - `./gradlew :btrace-instr:test` (default JDK 21)\n   - `JAVA_TEST_HOME=$(sdk home java 8.0.482-librca) ./gradlew :btrace-instr:test` (JDK 8)\n   - `JAVA_TEST_HOME=$(sdk home java 11.0.23-tem) ./gradlew :integration-tests:test -Pintegration`\n   - `JAVA_TEST_HOME=$(sdk home java 8.0.482-librca) ./gradlew :integration-tests:test -Pintegration`\n   - Push, wait for full CI matrix to go green.\n\n6. **Commit the fix** with message along the lines of `fix(agent): serialize probe load and detach to avoid runtime-registry race`.\n\n## Files with uncommitted WIP\n\n- `btrace-agent/src/main/java/org/openjdk/btrace/agent/Client.java` — added `synchronized` to `loadClass`.\n\n## Useful commands to reproduce state\n\n```bash\n# current branch / HEAD\ngit status\ngit log --oneline -8\n\n# which commit broke integration tests (bisect confirmed)\ngit log --oneline master..HEAD\n\n# inspect the raced methods\ngrep -n \"loadClass\\b\\|onExit\\b\\|synchronized\" btrace-agent/src/main/java/org/openjdk/btrace/agent/Client.java\ngrep -n \"runtimes\\.\\(clear\\|remove\\|put\\)\" btrace-runtime/src/main/java/org/openjdk/btrace/runtime/BTraceRuntimeAccessImpl.java\n\n# CI status\ngh pr checks 830\ngh api repos/btraceio/btrace/actions/jobs/72048627587/logs\ngh api repos/btraceio/btrace/actions/jobs/72048627596/logs\n\n# local reproduce\nsource ~/.sdkman/bin/sdkman-init.sh\nBTRACE_TEST_DEBUG=true JAVA_TEST_HOME=$(sdk home java 11.0.23-tem) \\\n    ./gradlew :integration-tests:test --tests 'tests.BTraceFunctionalTests.testOnMethodLevel' -Pintegration 2>&1 | tail -60\n```\n\n## Architectural context (for anyone new to the work)\n\n- PR #830 moved probe classes out of bootstrap CL into per-probe ClassLoaders (JDK 8/9-14) or hidden classes (JDK 15+) so that probe detach actually releases the class for unloading.\n- Handler `MethodHandle` cache moved from a static `HandlerRepositoryImpl.handlerCache` to a per-probe field on `BTraceProbeSupport`.\n- `BTraceRuntime.Impl.defineClass(byte[], boolean)` signature reduced to `(byte[])` — `mustBeBootstrap` was dead after the residency change.\n- New public primitive `BTraceRuntimes.removeRuntime(String)` added so callers can release the static runtime registry entry.\n- `Client.cleanupTransformers` wired to call `removeRuntime` at detach — **this wire-up is what introduced the race covered in this document**.\n\nFull implementation plan: `docs/plans/2026-04-20-probe-class-unloading.md`.\n\n## Memory (user prefs relevant to this work)\n\n- `JAVA_TEST_HOME=<path>` is the canonical way to run tests on a non-default JDK. Default dev JDK is 21.\n- sdkman has 8.0.482-librca, 11.0.23-tem, 11.0.17-tem, 17.0.5/8/11/13/14/18-tem, 21.0.x-tem variants available locally.\n- Do not leak internal phase/iteration labels (e.g. \"Phase 3\") into public javadoc or shipped comments.\n"
  },
  {
    "path": "docs/plans/2026-04-20-probe-class-unloading.md",
    "content": "# Probe Class Unloading Implementation Plan\n\n> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.\n\n**Goal:** Make BTrace probe classes unloadable on probe detach, so that long-running JVMs with repeated attach/detach cycles no longer accumulate probe classes in Metaspace indefinitely.\n\n**Architecture:** Replace the single-bootstrap-CL probe residency with (a) a per-probe isolated `ClassLoader` on JDK 8–14, and (b) a hidden class defined via `Lookup.defineHiddenClass(..., ClassOption.STRONG)` on JDK 15+. The probe `Class<?>` is stored on the `BTraceProbe` wrapper at `register()` time and cleared at `unregister()`. `HandlerRepositoryImpl.resolveHandler` stops calling `Class.forName` and instead reads the cached `Class<?>` from the probe. All existing dispatch mechanisms (`@OnMethod` via indy, `@OnTimer`/`@OnEvent`/`@OnError` via reflection-through-`Class<?>`) work unchanged because they already go through a held `Class<?>` reference, not name-based lookup.\n\n**Tech Stack:** Java 8+, ASM, `sun.misc.Unsafe` (JDK 8 define path), `MethodHandles.Lookup.defineClass` / `defineHiddenClass` (JDK 9+/15+), JUnit 5, Gradle.\n\n---\n\n## Scope\n\nThis plan covers **only** the class-residency change. It does **not** touch:\n\n- `HandlerRepositoryImpl.HandlerKey` (already landed on this branch).\n- `IndyDispatcher.invalidateProbe` noop mechanism — the noop handle is already defined on `IndyDispatcher` (bootstrap), so noop installation does not pin the probe class. Verify but do not modify.\n- The target-class instrumentation itself (INVOKEDYNAMIC emission). Unchanged.\n\n## File structure\n\nFiles modified (no new files created):\n\n- `btrace-core/src/main/java/org/openjdk/btrace/core/BTraceRuntime.java` — extend `Impl.defineClass` signature (add overload or drop `mustBeBootstrap` in a follow-up).\n- `btrace-runtime/src/main/java/org/openjdk/btrace/runtime/BTraceRuntimeImpl_8.java` — switch define path to per-probe CL.\n- `btrace-runtime/src/main/java9/org/openjdk/btrace/runtime/BTraceRuntimeImpl_9.java` — per-probe CL with anchor class.\n- `btrace-runtime/src/main/java11/org/openjdk/btrace/runtime/BTraceRuntimeImpl_11.java` — JDK 15+ hidden-class path with JDK 11–14 fallback to per-probe CL.\n- `btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbe.java` — add `getProbeClass()` to interface.\n- `btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbeSupport.java` — store/clear `Class<?>`.\n- `btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbeNode.java` — thread `probeClass` through `register`/`unregister`.\n- `btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbePersisted.java` — same.\n- `btrace-instr/src/main/java/org/openjdk/btrace/instr/HandlerRepositoryImpl.java` — drop `Class.forName`.\n\nNew / extended tests:\n\n- `btrace-instr/src/test/java/org/openjdk/btrace/instr/ProbeTestHelper.java` — **new**, extracted common helpers (`loadTestProbe`, `mockRuntime`, `mockTransformer`) from existing `HandlerRepositoryImplTest`.\n- `btrace-instr/src/test/java/org/openjdk/btrace/instr/ProbeClassUnloadingTest.java` — **new**. Asserts **weak reachability** after detach: `WeakReference<Class<?>>` / `WeakReference<ClassLoader>` cleared after dropping strong refs and a handful of `System.gc()` cycles. We do NOT assert \"Metaspace has actually unloaded the class\" — that is JVM-level and flaky under `System.gc()`; weak reachability is the reliable pre-condition and is deterministic.\n- `btrace-instr/src/test/java/org/openjdk/btrace/instr/HandlerRepositoryImplTest.java` — extend existing test with `getProbeClass()` path coverage.\n\n---\n\n## Task 1: Add `getProbeClass()` accessor on `BTraceProbe`\n\n(Task 0 from an earlier revision was dropped — the imagined `loadTestProbe`/`mockRuntime` helpers never existed. The real test harness uses `stubProbe(String internalName)` with lifecycle-only semantics; we extend it to optionally carry a `Class<?>` instead of standing up a compile-script helper.)\n\n**Files:**\n- Modify: `btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbe.java`\n- Modify: `btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbeSupport.java`\n- Modify: `btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbeNode.java`\n- Modify: `btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbePersisted.java`\n- Test: `btrace-instr/src/test/java/org/openjdk/btrace/instr/HandlerRepositoryImplTest.java`\n\n- [ ] **Step 1: Write failing test for `getProbeClass()` on registered probe**\n\nAppend to `HandlerRepositoryImplTest.java`:\n\n```java\n@Test\nvoid probeExposesDefinedClass() throws Exception {\n    BTraceProbe probe = loadTestProbe(\"TestProbe\");     // existing helper\n    probe.register(mockRuntime(), mockTransformer());\n    try {\n        Class<?> clz = probe.getProbeClass();\n        assertNotNull(clz, \"getProbeClass must return the defined Class after register()\");\n        assertEquals(probe.getClassName(true).replace('/', '.'), clz.getName());\n    } finally {\n        probe.unregister();\n    }\n}\n```\n\n- [ ] **Step 2: Run the test — verify compile failure (method does not exist)**\n\nRun: `./gradlew :btrace-instr:compileTestJava`\nExpected: compile error — `cannot find symbol: method getProbeClass()`.\n\n- [ ] **Step 3: Add accessor to the `BTraceProbe` interface**\n\nAdd to `BTraceProbe.java`:\n\n```java\n/**\n * @return the defined probe {@link Class}, or {@code null} if the probe has not been\n *         registered (or has been unregistered).\n */\nClass<?> getProbeClass();\n```\n\n- [ ] **Step 4: Back it with a field on `BTraceProbeSupport`**\n\nIn `BTraceProbeSupport.java`, modify `defineClass` to stash the result, and add accessor:\n\n```java\nprivate volatile Class<?> probeClass;\n\nClass<?> defineClass(BTraceRuntime.Impl rt, byte[] code) {\n    // ... existing body ...\n    Class<?> clz = rt.defineClass(code, isTransforming());\n    // ... existing logging ...\n    this.probeClass = clz;\n    return clz;\n}\n\n@Override\npublic Class<?> getProbeClass() {\n    return probeClass;\n}\n\nvoid clearProbeClass() {\n    this.probeClass = null;\n}\n```\n\n- [ ] **Step 5: Delegate `getProbeClass()` through `BTraceProbeNode` and `BTraceProbePersisted`**\n\nIn both `BTraceProbeNode.java` and `BTraceProbePersisted.java`, add:\n\n```java\n@Override\npublic Class<?> getProbeClass() {\n    return delegate.getProbeClass();\n}\n```\n\nClear it in both `unregister()` methods (immediately after `HandlerRepositoryImpl.unregisterProbe(this)`):\n\n```java\ndelegate.clearProbeClass();\n```\n\n- [ ] **Step 6: Run the test — verify pass**\n\nRun: `./gradlew :btrace-instr:test --tests org.openjdk.btrace.instr.HandlerRepositoryImplTest.probeExposesDefinedClass`\nExpected: PASS.\n\n- [ ] **Step 7: Commit**\n\n```bash\ngit add btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbe.java \\\n        btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbeSupport.java \\\n        btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbeNode.java \\\n        btrace-instr/src/main/java/org/openjdk/btrace/instr/BTraceProbePersisted.java \\\n        btrace-instr/src/test/java/org/openjdk/btrace/instr/HandlerRepositoryImplTest.java\ngit commit -m \"feat(instr): expose defined probe Class<?> on BTraceProbe\"\n```\n\n---\n\n## Task 2: Switch `HandlerRepositoryImpl.resolveHandler` to use `getProbeClass()` instead of `Class.forName`\n\n**Files:**\n- Modify: `btrace-instr/src/main/java/org/openjdk/btrace/instr/HandlerRepositoryImpl.java`\n- Test: `btrace-instr/src/test/java/org/openjdk/btrace/instr/HandlerRepositoryImplTest.java`\n\n- [ ] **Step 1: Write failing test — resolution must succeed even if the probe class is NOT resolvable by `Class.forName`**\n\nAppend to `HandlerRepositoryImplTest.java`:\n\n```java\n@Test\nvoid resolveHandlerUsesProbeCachedClass() throws Exception {\n    // Define a test probe class in a fresh ClassLoader so Class.forName on the current\n    // thread's CL would NOT find it. This verifies resolveHandler goes through\n    // probe.getProbeClass() and not Class.forName.\n    BTraceProbe probe = loadTestProbe(\"TestProbe\");\n    probe.register(mockRuntime(), mockTransformer());\n    try {\n        MethodHandle mh = HandlerRepositoryImpl.resolveHandler(\n            probe.getClassName(true),\n            probe.getClassName(true).replace('/', '_') + \"$onMethod\",\n            MethodType.methodType(void.class));\n        assertNotNull(mh);\n    } finally {\n        probe.unregister();\n    }\n}\n```\n\nAlso assert no `Class.forName` reachability: add a custom `ClassLoader` in the test that throws on name-based lookup to detect regression:\n\n```java\n@Test\nvoid resolveHandlerDoesNotUseClassForName() throws Exception {\n    BTraceProbe probe = loadTestProbe(\"TestProbe\");\n    probe.register(mockRuntime(), mockTransformer());\n    ClassLoader orig = Thread.currentThread().getContextClassLoader();\n    Thread.currentThread().setContextClassLoader(new ClassLoader(null) {\n        @Override\n        protected Class<?> loadClass(String name, boolean resolve) {\n            throw new AssertionError(\"resolveHandler must not use Class.forName: \" + name);\n        }\n    });\n    try {\n        HandlerRepositoryImpl.resolveHandler(\n            probe.getClassName(true),\n            probe.getClassName(true).replace('/', '_') + \"$onMethod\",\n            MethodType.methodType(void.class));\n    } finally {\n        Thread.currentThread().setContextClassLoader(orig);\n        probe.unregister();\n    }\n}\n```\n\n- [ ] **Step 2: Run tests — verify the `DoesNotUseClassForName` test fails**\n\nRun: `./gradlew :btrace-instr:test --tests HandlerRepositoryImplTest.resolveHandlerDoesNotUseClassForName`\nExpected: FAIL — current code calls `Class.forName`.\n\n- [ ] **Step 3: Replace `Class.forName` with `probe.getProbeClass()`**\n\nIn `HandlerRepositoryImpl.java`, replace the body of `resolveHandler`:\n\n```java\npublic static MethodHandle resolveHandler(\n    String probeName, String handlerName, MethodType handlerType) {\n  HandlerKey cacheKey = new HandlerKey(probeName, handlerName, handlerType);\n  MethodHandle cached = handlerCache.get(cacheKey);\n  if (cached != null) {\n    return cached;\n  }\n\n  BTraceProbe probe = probeMap.get(probeName);\n  if (probe == null) {\n    return null;\n  }\n  Class<?> probeClass = probe.getProbeClass();\n  if (probeClass == null) {\n    // defineClass has not populated probeClass yet (race with register()).\n    return null;\n  }\n\n  try {\n    int dollarIdx = handlerName.lastIndexOf('$');\n    String simpleHandlerName =\n        dollarIdx >= 0 ? handlerName.substring(dollarIdx + 1) : handlerName;\n\n    MethodHandle mh =\n        MethodHandles.publicLookup().findStatic(probeClass, simpleHandlerName, handlerType);\n    handlerCache.put(cacheKey, mh);\n\n    if (SharedSettings.GLOBAL.isDumpClasses()) {\n      log.debug(\"BTrace INDY handler resolved: {}.{}\", probeName, simpleHandlerName);\n    }\n    return mh;\n  } catch (Throwable e) {\n    log.warn(\"Failed to resolve handler '{}' in probe '{}'\", handlerName, probeName, e);\n    return null;\n  }\n}\n```\n\n- [ ] **Step 4: Run all `HandlerRepositoryImplTest` tests**\n\nRun: `./gradlew :btrace-instr:test --tests HandlerRepositoryImplTest`\nExpected: all PASS.\n\n- [ ] **Step 5: Commit**\n\n```bash\ngit add btrace-instr/src/main/java/org/openjdk/btrace/instr/HandlerRepositoryImpl.java \\\n        btrace-instr/src/test/java/org/openjdk/btrace/instr/HandlerRepositoryImplTest.java\ngit commit -m \"refactor(instr): resolve probe handler via probe.getProbeClass(), not Class.forName\"\n```\n\n---\n\n## Task 3: JDK 8 — switch probe define to per-probe ClassLoader\n\n**Files:**\n- Modify: `btrace-runtime/src/main/java/org/openjdk/btrace/runtime/BTraceRuntimeImpl_8.java`\n- Test: `btrace-instr/src/test/java/org/openjdk/btrace/instr/ProbeClassUnloadingTest.java` (new)\n\n- [ ] **Step 1: Write failing reachability test**\n\nCreate `btrace-instr/src/test/java/org/openjdk/btrace/instr/ProbeClassUnloadingTest.java`:\n\n```java\npackage org.openjdk.btrace.instr;\n\nimport java.lang.ref.WeakReference;\nimport org.junit.jupiter.api.Test;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\n\nclass ProbeClassUnloadingTest {\n\n    /**\n     * Verifies that after probe.unregister() and dropping all caller-held references,\n     * BTrace's own internal state retains no strong references to the probe class or\n     * its ClassLoader. We assert weak reachability, NOT Metaspace unloading — actual\n     * unloading depends on JVM-level GC policy which is non-deterministic under\n     * System.gc() and flaky on CI.\n     */\n    @Test\n    void probeClassWeaklyReachableAfterDetach() throws Exception {\n        BTraceProbe probe = ProbeTestHelper.loadTestProbe(\"TestProbe\");\n        probe.register(ProbeTestHelper.mockRuntime(), ProbeTestHelper.mockTransformer());\n        Class<?> probeClass = probe.getProbeClass();\n        assertNotNull(probeClass, \"register() must populate probeClass\");\n        WeakReference<Class<?>> weakClass = new WeakReference<>(probeClass);\n        ClassLoader probeLoader = probeClass.getClassLoader();\n        WeakReference<ClassLoader> weakLoader = probeLoader != null\n            ? new WeakReference<>(probeLoader) : null;\n\n        probe.unregister();\n        // Drop all strong references the test holds\n        probe = null;\n        probeClass = null;\n        probeLoader = null;\n\n        // A few cycles are typically enough for soft/weak refs; we do not require\n        // Metaspace unload here — only weak reachability.\n        for (int i = 0; i < 20; i++) {\n            System.gc();\n            Thread.sleep(50);\n            if (weakClass.get() == null && (weakLoader == null || weakLoader.get() == null)) {\n                break;\n            }\n        }\n        assertNull(weakClass.get(),\n            \"probe Class<?> is still strongly reachable from BTrace internal state after detach\");\n        if (weakLoader != null) {\n            assertNull(weakLoader.get(),\n                \"probe ClassLoader is still strongly reachable after detach\");\n        }\n    }\n}\n```\n\n- [ ] **Step 2: Run the test — verify it fails (bootstrap CL → no unload)**\n\nRun: `./gradlew :btrace-instr:test --tests org.openjdk.btrace.instr.ProbeClassUnloadingTest`\nExpected: FAIL — `loaderRef.get()` is `null` because probe is in bootstrap CL, but `weakRef.get()` is not `null`.\n\n- [ ] **Step 3: Change `BTraceRuntimeImpl_8.defineClass` to always use a fresh isolated CL**\n\nReplace body of `defineClass` at BTraceRuntimeImpl_8.java:131:\n\n```java\n@Override\npublic Class<?> defineClass(byte[] code, boolean mustBeBootstrap) {\n    Unsafe unsafe = BTraceRuntime.initUnsafe();\n    if (unsafe == null) return null;\n\n    StackTraceElement[] stack = Thread.currentThread().getStackTrace();\n    String callerClassName = stack.length > 2 ? stack[2].getClassName() : null;\n    if (callerClassName == null || !callerClassName.startsWith(\"org.openjdk.btrace.\")) {\n        throw new SecurityException(\"unsafe defineClass\");\n    }\n\n    // Per-probe ClassLoader with bootstrap as parent. This loader becomes\n    // unreachable (and the probe class unloadable) once the probe is unregistered\n    // and all MethodHandles/Call sites referencing the class are cleared.\n    // `mustBeBootstrap` is retained in the signature for API compat but no longer\n    // forces bootstrap residency — the current dispatch model (indy bootstrap via\n    // IndyDispatcher + MethodHandle) does not require the probe class to be\n    // visible by name from the target class's CL.\n    ClassLoader loader = new ClassLoader(null) {};\n    Class<?> cl = unsafe.defineClass(getClassName(), code, 0, code.length, loader, null);\n    unsafe.ensureClassInitialized(cl);\n    return cl;\n}\n```\n\n- [ ] **Step 4: Run the unload test on JDK 8**\n\nRun: `./gradlew :btrace-instr:test --tests org.openjdk.btrace.instr.ProbeClassUnloadingTest -PtestJdk=8`\nExpected: PASS (the loader is unreachable, class unloads after GC).\n\n- [ ] **Step 5: Run the existing instrumentor test suite to catch regressions**\n\nRun: `./gradlew :btrace-instr:test`\nExpected: all existing tests PASS.\n\nLikely regressions to debug if any fail:\n- Any test that asserts probe class is in bootstrap CL → rewrite to assert per-probe CL instead.\n- Any test that does `Class.forName(probeName)` → rewrite to use `probe.getProbeClass()`.\n\n- [ ] **Step 6: Commit**\n\n```bash\ngit add btrace-runtime/src/main/java/org/openjdk/btrace/runtime/BTraceRuntimeImpl_8.java \\\n        btrace-instr/src/test/java/org/openjdk/btrace/instr/ProbeClassUnloadingTest.java\ngit commit -m \"feat(runtime): define probes in per-probe ClassLoader on JDK 8\"\n```\n\n---\n\n## Task 4: JDK 9+ — per-probe anchor class + CL\n\n**Files:**\n- Modify: `btrace-runtime/src/main/java9/org/openjdk/btrace/runtime/BTraceRuntimeImpl_9.java`\n\n**Design:** We need to call `MethodHandles.privateLookupIn(anchor, lookup()).defineClass(code)` — this defines the class in `anchor`'s package and loader. Per-probe anchor means per-probe loader. Generate a minimal anchor class (empty body) into a fresh unnamed `ClassLoader`, then define the probe class into the same loader via that anchor.\n\n- [ ] **Step 1: Run the unload test on JDK 9+ (before change)**\n\nRun: `./gradlew :btrace-instr:test --tests org.openjdk.btrace.instr.ProbeClassUnloadingTest -PtestJdk=11`\nExpected: FAIL on JDK 9+ with current code (probe in `Auxiliary`'s bootstrap loader).\n\n- [ ] **Step 2: Write a helper in `BTraceRuntimeImpl_9.java` to generate a per-probe anchor class**\n\nAdd a private helper that generates a minimal ASM classfile for `org.openjdk.btrace.runtime.auxiliary.Anchor$<unique>` and defines it in a fresh `ClassLoader`:\n\n```java\nprivate static final java.util.concurrent.atomic.AtomicLong ANCHOR_SEQ =\n    new java.util.concurrent.atomic.AtomicLong();\n\nprivate static Class<?> defineAnchorInFreshLoader() throws Exception {\n    long id = ANCHOR_SEQ.incrementAndGet();\n    String internalName = \"org/openjdk/btrace/runtime/auxiliary/Anchor$\" + id;\n    String binaryName = internalName.replace('/', '.');\n\n    org.objectweb.asm.ClassWriter cw = new org.objectweb.asm.ClassWriter(0);\n    cw.visit(org.objectweb.asm.Opcodes.V1_8,\n             org.objectweb.asm.Opcodes.ACC_PUBLIC | org.objectweb.asm.Opcodes.ACC_FINAL,\n             internalName, null, \"java/lang/Object\", null);\n    org.objectweb.asm.MethodVisitor mv = cw.visitMethod(\n        org.objectweb.asm.Opcodes.ACC_PUBLIC, \"<init>\", \"()V\", null, null);\n    mv.visitCode();\n    mv.visitVarInsn(org.objectweb.asm.Opcodes.ALOAD, 0);\n    mv.visitMethodInsn(org.objectweb.asm.Opcodes.INVOKESPECIAL, \"java/lang/Object\", \"<init>\", \"()V\", false);\n    mv.visitInsn(org.objectweb.asm.Opcodes.RETURN);\n    mv.visitMaxs(1, 1);\n    mv.visitEnd();\n    cw.visitEnd();\n    byte[] anchorBytes = cw.toByteArray();\n\n    ClassLoader loader = new ClassLoader(null) {\n        @Override\n        protected Class<?> findClass(String name) throws ClassNotFoundException {\n            if (name.equals(binaryName)) {\n                return defineClass(name, anchorBytes, 0, anchorBytes.length);\n            }\n            throw new ClassNotFoundException(name);\n        }\n    };\n    return Class.forName(binaryName, true, loader);\n}\n```\n\n- [ ] **Step 3: Replace `BTraceRuntimeImpl_9.defineClass` body**\n\n```java\n@Override\npublic Class<?> defineClass(byte[] code, boolean mustBeBootstrap) {\n    try {\n        StackWalker.StackFrame frame =\n            StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)\n                .walk(s -> s.skip(1).findFirst().orElse(null));\n        Class<?> caller = frame != null ? frame.getDeclaringClass() : null;\n        if (caller == null || !caller.getName().startsWith(\"org.openjdk.btrace.\")) {\n            throw new SecurityException(\"unsafe defineClass\");\n        }\n\n        Class<?> anchor = defineAnchorInFreshLoader();\n        Class<?> clz = MethodHandles.privateLookupIn(anchor, MethodHandles.lookup())\n                                    .defineClass(code);\n        clz.getConstructor().newInstance();\n        return clz;\n    } catch (Throwable t) {\n        // fall through, behavior matches pre-change\n        log.debug(\"Failed to define probe class\", t);\n        return null;\n    }\n}\n```\n\n- [ ] **Step 4: Run unload test on JDK 11**\n\nRun: `./gradlew :btrace-instr:test --tests org.openjdk.btrace.instr.ProbeClassUnloadingTest -PtestJdk=11`\nExpected: PASS.\n\n- [ ] **Step 5: Run full test suite on JDK 11**\n\nRun: `./gradlew :btrace-instr:test :btrace-runtime:test -PtestJdk=11`\nExpected: all PASS.\n\n- [ ] **Step 6: Commit**\n\n```bash\ngit add btrace-runtime/src/main/java9/org/openjdk/btrace/runtime/BTraceRuntimeImpl_9.java\ngit commit -m \"feat(runtime): define probes in per-probe ClassLoader on JDK 9-14\"\n```\n\n---\n\n## Task 5: JDK 15+ — use hidden classes\n\n**Files:**\n- Modify: `btrace-runtime/src/main/java11/org/openjdk/btrace/runtime/BTraceRuntimeImpl_11.java`\n\n**Design:** On JDK 15+, `MethodHandles.Lookup.defineHiddenClass(bytes, initialize, ClassOption.STRONG)` yields a class whose lifetime is tied to `Class<?>` reachability. No per-probe CL needed — cleaner. On JDK 11–14, fall back to the per-probe-CL path from Task 4.\n\n- [ ] **Step 1: Write failing test — on JDK 15+, `getProbeClass().isHidden()` must be true**\n\nAppend to `ProbeClassUnloadingTest.java`:\n\n```java\n@Test\n@EnabledOnJre({JRE.JAVA_15, JRE.JAVA_16, JRE.JAVA_17, JRE.JAVA_18, JRE.JAVA_19,\n               JRE.JAVA_20, JRE.JAVA_21, JRE.JAVA_22, JRE.JAVA_23, JRE.JAVA_24, JRE.JAVA_25})\nvoid probeClassIsHiddenOnJdk15Plus() throws Exception {\n    BTraceProbe probe = ProbeTestHelper.loadTestProbe(\"TestProbe\");\n    probe.register(ProbeTestHelper.mockRuntime(), ProbeTestHelper.mockTransformer());\n    try {\n        assertTrue(probe.getProbeClass().isHidden());\n    } finally {\n        probe.unregister();\n    }\n}\n```\n\n- [ ] **Step 2: Run the test — verify it fails (probe is a named class)**\n\nRun: `./gradlew :btrace-instr:test --tests org.openjdk.btrace.instr.ProbeClassUnloadingTest.probeClassIsHiddenOnJdk15Plus -PtestJdk=17`\nExpected: FAIL.\n\n- [ ] **Step 3: Add a hidden-class path in `BTraceRuntimeImpl_11.defineClass`, gated on `Runtime.Version`**\n\n```java\n@Override\npublic Class<?> defineClass(byte[] code, boolean mustBeBootstrap) {\n    try {\n        // Caller validation (unchanged)\n        StackWalker.StackFrame frame = /* ... */;\n        Class<?> caller = frame != null ? frame.getDeclaringClass() : null;\n        if (caller == null || !caller.getName().startsWith(\"org.openjdk.btrace.\")) {\n            throw new SecurityException(\"unsafe defineClass\");\n        }\n\n        if (Runtime.version().feature() >= 15) {\n            // Hidden class: lifetime tied to Class<?> reachability. No per-probe CL needed.\n            MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(\n                Auxiliary.class, MethodHandles.lookup());\n            Class<?> clz = lookup.defineHiddenClass(\n                code, true, MethodHandles.Lookup.ClassOption.STRONG).lookupClass();\n            return clz;\n        }\n\n        // JDK 11–14: per-probe CL path (same as Task 4 for JDK 9)\n        Class<?> anchor = defineAnchorInFreshLoader();\n        Class<?> clz = MethodHandles.privateLookupIn(anchor, MethodHandles.lookup())\n                                    .defineClass(code);\n        clz.getConstructor().newInstance();\n        return clz;\n    } catch (Throwable t) {\n        log.debug(\"Failed to define probe class\", t);\n        return null;\n    }\n}\n```\n\nNote: hidden classes skip `clz.getConstructor().newInstance()` init — hidden classes are initialized automatically by `defineHiddenClass(..., true, ...)`.\n\nNote 2: `publicLookup().findStatic(probeClass, name, type)` on a hidden class requires that the hidden class's own lookup allow it, OR that we use the lookup used to define the class. Hidden classes' handler methods are accessible via `publicLookup()` only if they are both `public` and in a readable module. The probe class is defined via `privateLookupIn(Auxiliary.class)` — Auxiliary's module/package. Probe handler methods generated by the compiler are `public static`. **Verify:** run the indy dispatch path against a hidden probe and confirm `publicLookup().findStatic` succeeds; if not, thread the defining `Lookup` into `HandlerRepositoryImpl` (e.g., add `getProbeLookup()` to `BTraceProbe`).\n\n- [ ] **Step 4: Run hidden-class test**\n\nRun: `./gradlew :btrace-instr:test --tests org.openjdk.btrace.instr.ProbeClassUnloadingTest.probeClassIsHiddenOnJdk15Plus -PtestJdk=17`\nExpected: PASS.\n\n- [ ] **Step 5: Run the full unload test on JDK 17**\n\nRun: `./gradlew :btrace-instr:test --tests org.openjdk.btrace.instr.ProbeClassUnloadingTest -PtestJdk=17`\nExpected: both tests PASS.\n\n- [ ] **Step 6: If `publicLookup().findStatic` fails for hidden classes, add `getProbeLookup()`**\n\nIf Step 4 fails with `IllegalAccessException`:\n\n  a. Add to `BTraceRuntime.Impl.defineClass` return type an alternative that also returns a `Lookup`. Simplest: add a new method `Lookup defineProbeClassAndLookup(byte[] code, boolean mustBeBootstrap)` and deprecate the old one; have `defineClass` call it and drop the Lookup for back-compat consumers.\n\n  b. Store the `Lookup` on `BTraceProbeSupport` alongside `probeClass`. Expose `getProbeLookup()` on `BTraceProbe`.\n\n  c. In `HandlerRepositoryImpl.resolveHandler`, prefer `probe.getProbeLookup().findStatic(...)` if non-null, else fall back to `publicLookup().findStatic(...)`.\n\nWrite a test asserting resolution works on hidden probe classes before and after this fix.\n\n- [ ] **Step 7: Run full cross-JDK test matrix**\n\nRun: `./gradlew :btrace-instr:test` (on CI, sweep across JDK 8/11/17/21/25).\nExpected: all PASS.\n\n- [ ] **Step 8: Commit**\n\n```bash\ngit add btrace-runtime/src/main/java11/org/openjdk/btrace/runtime/BTraceRuntimeImpl_11.java \\\n        btrace-instr/src/test/java/org/openjdk/btrace/instr/ProbeClassUnloadingTest.java\n# (if Step 6 was needed, also add BTraceProbe, BTraceProbeSupport, Node, Persisted, HandlerRepositoryImpl)\ngit commit -m \"feat(runtime): use hidden classes for probes on JDK 15+\"\n```\n\n---\n\n## Task 6: Verify `@OnTimer`/`@OnEvent`/`@OnError` still work with per-probe CL\n\n**Files:**\n- Test: `btrace-instr/src/test/java/org/openjdk/btrace/instr/ProbeLifecycleCallbacksTest.java` (new, or extend existing functional test)\n\n- [ ] **Step 1: Identify existing functional-test probe scripts covering timer/event/error callbacks**\n\nRun: `grep -rn \"@OnTimer\\|@OnEvent\\|@OnError\" integration-tests/src/test/btrace`\nRecord file names — these are the probe scripts used by `BTraceFunctionalTests`.\n\n- [ ] **Step 2: Run the existing functional-test suite**\n\nRun: `./gradlew :integration-tests:test`\nExpected: all PASS. If any fail due to `Class.forName`/CL visibility assumptions, triage.\n\n- [ ] **Step 3: Add a minimal regression test that specifically exercises @OnTimer + detach + re-attach**\n\nCreate `integration-tests/src/test/java/tests/ProbeReattachTest.java`:\n\n```java\n@Test\nvoid reattachSameProbeScriptDoesNotCollide() throws Exception {\n    // Attach a probe with @OnTimer; let it tick once; detach.\n    runFunctionalTest(\"OnTimerProbe.java\", /*duration*/ 2000);\n    // Re-attach the SAME script. With bootstrap CL this would throw LinkageError\n    // (class already defined). With per-probe CL / hidden class, it succeeds.\n    runFunctionalTest(\"OnTimerProbe.java\", /*duration*/ 2000);\n}\n```\n\n- [ ] **Step 4: Run the new regression test**\n\nRun: `./gradlew :integration-tests:test --tests ProbeReattachTest`\nExpected: PASS.\n\n- [ ] **Step 5: Commit**\n\n```bash\ngit add integration-tests/src/test/java/tests/ProbeReattachTest.java\ngit commit -m \"test(integration): verify probe re-attach does not collide with per-probe CL\"\n```\n\n---\n\n## Task 7: Documentation + final cleanup\n\n**Files:**\n- Modify: `btrace-instr/src/main/java/org/openjdk/btrace/instr/HandlerRepositoryImpl.java` (javadoc)\n- Modify: `btrace-runtime/src/main/java/org/openjdk/btrace/runtime/IndyDispatcher.java` (update `Why always MutableCallSite` section to mention class unloading)\n\n- [ ] **Step 1: Update `IndyDispatcher` class javadoc**\n\nThe current `Why always MutableCallSite` paragraph says probe classes stay in bootstrap CL. After this change, that's no longer the reason — instead, the reason is that instrumentation in target classes persists after detach (no retransform-on-detach), so live call sites must be relinkable to a noop to avoid NPEs. Update wording to reflect this.\n\n- [ ] **Step 2: Update `HandlerRepositoryImpl` javadoc**\n\nRemove the stale comment about \"probe classes are defined in the bootstrap CL (via Unsafe.defineClass with loader=null)\". Replace with: \"probe classes are defined in per-probe ClassLoaders (JDK 8–14) or as hidden classes (JDK 15+); the Class reference is kept on the BTraceProbe wrapper and cleared on unregister().\"\n\n- [ ] **Step 3: Run the full test suite one more time**\n\nRun: `./gradlew check`\nExpected: all PASS.\n\n- [ ] **Step 4: Commit**\n\n```bash\ngit add btrace-instr/src/main/java/org/openjdk/btrace/instr/HandlerRepositoryImpl.java \\\n        btrace-runtime/src/main/java/org/openjdk/btrace/runtime/IndyDispatcher.java\ngit commit -m \"docs: update dispatch/repository javadoc for per-probe CL / hidden class residency\"\n```\n\n---\n\n## Risks and mitigations\n\n| Risk | Mitigation |\n|------|-----------|\n| Hidden-class probe not resolvable via `publicLookup().findStatic` due to module access | Task 5 Step 6 contingency: thread the defining `Lookup` through `BTraceProbe`. Test before merging. |\n| Some existing test asserts probe is in bootstrap CL | Task 3 Step 5 — triage during run; expected to surface only as targeted test assertions, not functional breakage. |\n| Per-probe CL allocation overhead | One CL per probe attach. Detach is rare. Negligible. |\n| MH cache in `HandlerRepositoryImpl.handlerCache` pinning probe class after detach | `unregisterProbe` already evicts via `handlerCache.keySet().removeIf(k -> k.probe.equals(probeName))` — verified. Add a `WeakReference<MethodHandle>` experiment only if we observe MH-retention issues in practice. |\n| JDK 8 `Unsafe.defineClass` with a non-null loader + name collision across probes | Probe class names are generated with per-attach unique suffixes by the compiler (verify). If not, generate a unique suffix at define time. |\n| `MutableCallSite` noop target pinning probe class | Already verified OK — `IndyDispatcher.noopImpl` is in bootstrap CL (IndyDispatcher.java:103-104). |\n| Tests on CI run across JDK 8/11/17/21/25 — hidden-class path only exercised on 15+ | Task 5 uses `@EnabledOnJre` to gate. Unload test (Task 3) is JDK-agnostic and runs everywhere. |\n\n## Out of scope (future work)\n\n- Deduping same-script re-submissions by bytecode hash.\n- Converting `handlerCache` to `WeakHashMap<Class<?>, ...>` keyed by the probe class for natural eviction (would eliminate the `keySet().removeIf` scan).\n- Flattening `BTraceRuntime.Impl.defineClass`'s `mustBeBootstrap` parameter (now always effectively `false`).\n\n## Self-review\n\n- Spec coverage: per-probe CL on JDK 8/9/11 (Tasks 3/4), hidden classes on JDK 15+ (Task 5), accessor on BTraceProbe (Task 1), HandlerRepositoryImpl change (Task 2), runtime callback compatibility (Task 6), docs (Task 7). Covered.\n- Placeholder scan: every step has concrete code or commands. No TBD, no \"add validation\", no \"similar to Task N\".\n- Type consistency: `getProbeClass()`, `clearProbeClass()`, `probeMap`, `HandlerKey`, `probe.register()` names consistent across tasks.\n"
  },
  {
    "path": "docs/plans/DistributionRestructuring.md",
    "content": "# Plan: InvokeDynamic Isolation (Distribution Phase 3)\n\n**Status:** Not Started\n**Target:** v3.x (long-term)\n**Prerequisites:** Masked JAR architecture (completed, see [MaskedJarArchitecture.md](../architecture/MaskedJarArchitecture.md))\n\n## Background\n\nThe current masked JAR architecture reduces bootstrap classloader pollution to ~112 classes. This plan proposes further reducing the bootstrap footprint to ~50 KB by replacing direct method calls in instrumented bytecode with `invokedynamic` instructions, following the approach pioneered by Elastic APM.\n\n## Goal\n\nReduce the bootstrap classloader footprint from ~112 classes (~200 KB) to a single dispatcher class (~50 KB) by routing all instrumented bytecode through `invokedynamic`.\n\n## Architecture\n\nBased on Elastic APM's approach: instrumented bytecode uses `INVOKEDYNAMIC` instead of direct calls to BTrace runtime API. A tiny `IndyDispatcher` in the bootstrap classloader resolves these calls at first invocation.\n\n```\nbtrace-bootstrap-minimal.jar (~50 KB)\n└── org/openjdk/btrace/indy/\n    └── IndyDispatcher.java         # Only class in bootstrap CL\n```\n\n**Current:** Instrumented bytecode directly calls BTrace runtime API (requires API in bootstrap CL).\n**Proposed:** Instrumented bytecode uses `INVOKEDYNAMIC`, resolved by `IndyDispatcher`. The actual runtime API lives in an isolated classloader, not bootstrap.\n\n### Benefits\n\n- Minimal bootstrap footprint (~50 KB vs ~200 KB)\n- Better classloader isolation (no BTrace types leaked to application)\n- No dependency shading needed (runtime in isolated CL)\n- JIT can inline through `invokedynamic` (no performance loss after warmup)\n- Cleaner architecture aligned with industry best practices\n\n### Risks\n\n- Requires rewriting all instrumentation code generation\n- Higher implementation complexity\n- Requires Java 7+ (already satisfied: BTrace requires Java 8+)\n- Debugging instrumented code is harder (indirect calls)\n- First-call overhead from `invokedynamic` resolution (mitigated by JIT)\n\n## Implementation Outline\n\n1. Create `IndyDispatcher` bootstrap class with `CallSite` factory methods\n2. Modify `Instrumentor` to emit `INVOKEDYNAMIC` instead of `INVOKESTATIC` for BTrace runtime calls\n3. Move runtime API out of bootstrap into agent-isolated classloader\n4. Update `MaskedClassLoader` to serve as the isolated runtime CL\n5. Remove bootstrap classes except `IndyDispatcher`\n6. Comprehensive testing: all instrumentation tests must pass with new dispatch\n\n## References\n\n- [Elastic APM invokedynamic Blog](https://www.elastic.co/blog/embracing-invokedynamic-to-tame-class-loaders-in-java-agents)\n- [OpenTelemetry Java Agent Structure](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/contributing/javaagent-structure.md)\n- [Masked JAR Architecture](../architecture/MaskedJarArchitecture.md) (current approach)\n"
  },
  {
    "path": "docs/plans/TestCoverageImprovementPlan.md",
    "content": "# Test Coverage Improvement Plan\n\n**Status:** Partially Implemented (60% Complete)\n**Created:** 2026-01-31\n**Last Updated:** 2026-01-31\n**Target Version:** 2.3.1 or 2.4.0\n\n---\n\n## Overview\n\nThis plan addresses five testing gaps identified in the 2.3.0 readiness review. Three of the five gaps have been addressed with comprehensive test coverage.\n\n### Implementation Status\n\n| Priority | Testing Gap | Status | Tests Added |\n|----------|-------------|--------|-------------|\n| HIGH | Extension Lifecycle Tests | ✅ Complete | 3 integration tests |\n| MEDIUM | Oneliner Runtime Tests | ✅ Complete | 6 integration tests |\n| MEDIUM | Extension CLI Module Tests | ✅ Complete | 24 unit tests |\n| HIGH | V2 Protocol Integration Tests | ⏸️ Deferred | 0 (strong unit coverage exists) |\n| LOW | Extension Concurrency Tests | ⏸️ Pending | 0 (basic coverage exists) |\n\n**Overall Progress:** 3 of 5 gaps addressed (60%)\n\n---\n\n## 1. Extension Lifecycle Integration Tests ✅\n\n### Problem Statement\n\nNo test verified that Extension.initialize() and close() are called correctly during script lifecycle.\n\n### Implementation\n\n**Status:** ✅ **COMPLETE**\n\n#### Test Class\n\n**File:** `integration-tests/src/test/java/tests/ExtensionLifecycleIntegrationTest.java`\n\nCreated 3 integration tests using existing PrinterService extension:\n\n1. **testExtensionInitializeAndCloseCalled()** - Validates extension initialized, used, and closed in correct sequence when script detaches normally\n2. **testExtensionCloseCalledOnError()** - Verifies close() called even when script exits with error code\n3. **testMultipleExtensionsAllClosed()** - Confirms multiple injected extensions (PrinterService + MetricsService) all receive proper lifecycle callbacks\n\n#### BTrace Test Scripts\n\nCreated three new BTrace scripts for testing:\n\n- `integration-tests/src/test/btrace/ExtensionLifecycleFullTest.java` - Normal lifecycle test\n- `integration-tests/src/test/btrace/ExtensionLifecycleErrorTest.java` - Error exit test\n- `integration-tests/src/test/btrace/ExtensionLifecycleMultipleTest.java` - Multiple extensions test\n\n#### Test Execution\n\n```bash\n./gradlew :integration-tests:test --tests \"ExtensionLifecycleIntegrationTest\" -Pintegration\n```\n\n**Results:** All 3 tests passing ✓\n\n### Key Design Decisions\n\n- Used existing PrinterService extension instead of creating custom test extension\n- PrinterService includes lifecycle tracking via `extensionCloseTest` argument\n- Tests use `unattended = true` to trigger script detachment and close() invocation\n- Validates lifecycle events appear in stdout in correct order\n\n---\n\n## 2. Oneliner Runtime Integration Tests ✅\n\n### Problem Statement\n\nThe oneliner language had parser/generator tests but no end-to-end runtime validation.\n\n### Implementation\n\n**Status:** ✅ **COMPLETE**\n\n#### Test Class\n\n**File:** `integration-tests/src/test/java/tests/BTraceFunctionalTests.java` (enhanced)\n\nAdded 6 new integration test methods:\n\n1. **testOnelinerMethodEntry()** - Basic method entry probe: `Class::method @entry { print method }`\n2. **testOnelinerWithArguments()** - Argument capture: `@entry { print args }`\n3. **testOnelinerWithReturn()** - Return location: `@return { print method, duration }`\n4. **testOnelinerWithRegexClassMatch()** - Regex patterns: `/regex\\\\.pattern/::method`\n5. **testOnelinerStack()** - Stack trace action: `{ stack }`\n6. **testOnelinerCompilationError()** - Error handling for invalid syntax\n\n#### Oneliner Syntax Tested\n\n```bash\n# Method entry\nresources.Main::callA @entry { print method }\n\n# Arguments\nresources.Main::callB @entry { print args }\n\n# Return value\nresources.Main::callB @return { print method, duration }\n\n# Regex class match\n/resources\\..*Main/::callA @entry { print method }\n\n# Stack traces\nresources.Main::callB @entry { stack }\n\n# Error handling\nresources.Main::callB @invalid { print }  # Triggers error\n```\n\n#### Test Execution\n\n```bash\n./gradlew :integration-tests:test --tests \"BTraceFunctionalTests.testOneliner*\" -Pintegration\n```\n\n**Results:** All 6 tests passing ✓ (plus 1 existing testOnelinerRuntime)\n\n### Key Design Decisions\n\n- Used existing `testDynamicOneliner()` infrastructure from RuntimeTest\n- Oneliner strings are inline in test code (no separate fixture files)\n- Tests validate actual runtime behavior, not just compilation\n- Error test validates helpful error messages for invalid syntax\n\n---\n\n## 3. Extension CLI Module Tests ✅\n\n### Problem Statement\n\nThe `btrace-ext-cli` module had only 4 PolicyFileTest tests, no coverage for inspection, listing, or installation commands.\n\n### Implementation\n\n**Status:** ✅ **COMPLETE**\n\n#### Test Utility\n\n**File:** `btrace-ext-cli/src/test/java/org/openjdk/btrace/extcli/TestExtensionBuilder.java`\n\nHelper class to programmatically create valid extension JARs and ZIPs:\n\n- `createApiJar()` - Creates API JAR with manifest, exports index, permissions\n- `createImplJar()` - Creates implementation JAR with service entries\n- `createExtensionZip()` - Creates complete extension ZIP\n- `createExtensionDirectory()` - Creates extension directory structure\n\n#### Test Classes\n\n**File:** `btrace-ext-cli/src/test/java/org/openjdk/btrace/extcli/ExtensionInspectorTest.java`\n\n6 tests for extension inspection:\n\n1. `inspectValidDirectory()` - Inspects extension from directory\n2. `inspectValidZip()` - Inspects extension from ZIP file\n3. `detectMissingApiJar()` - Error handling for missing API JAR\n4. `detectMissingImplJar()` - Error handling for missing impl JAR\n5. `inspectExtensionWithPermissions()` - Extensions with permissions.properties\n6. `extractManifestId()` - ID extraction from JAR manifest\n\n**File:** `btrace-ext-cli/src/test/java/org/openjdk/btrace/extcli/ExtensionListerTest.java`\n\n4 tests for extension listing:\n\n1. `listFromBtraceHome()` - Lists extensions from BTRACE_HOME/extensions\n2. `listWithJsonFormat()` - JSON output format validation\n3. `listHandlesEmptyDirectories()` - Graceful empty directory handling\n4. `listOutputsExtensionInfo()` - General listing functionality\n\n**File:** `btrace-ext-cli/src/test/java/org/openjdk/btrace/extcli/InstallerTest.java`\n\n8 tests for extension installation:\n\n1. `dryRunFromLocalZip()` - Dry-run with local ZIP file\n2. `dryRunFromUrl()` - Dry-run with URL download\n3. `dryRunFromMavenGav()` - Dry-run with Maven coordinates\n4. `dryRunWithCustomId()` - Custom extension ID support\n5. `invalidGavCoordinateThrowsException()` - Error handling\n6. `unrecognizedInputThrowsException()` - Error handling\n7. `multipleReposInDryRun()` - Multiple Maven repository support\n8. `derivesIdFromZipFilename()` - ID derivation from filename\n\n**File:** `btrace-ext-cli/src/test/java/org/openjdk/btrace/extcli/MainTest.java`\n\n5 tests for CLI command parsing:\n\n1. `showsHelpWithNoArgs()` - Help output with no arguments\n2. `showsHelpWithHelpFlag()` - Help flag handling\n3. `inspectCommandWithValidExtension()` - Inspect command execution\n4. `inspectCommandWithJsonFlag()` - JSON output for inspect\n5. `listCommandExecutes()` - List command execution\n6. `unknownCommandShowsError()` - Unknown command error handling\n\n#### Build Configuration\n\n**File:** `btrace-ext-cli/build.gradle`\n\nAdded JUnit 5 dependencies:\n\n```gradle\ntestImplementation platform('org.junit:junit-bom:5.9.1')\ntestImplementation 'org.junit.jupiter:junit-jupiter'\n\ntest {\n    useJUnitPlatform()\n}\n```\n\n#### Test Execution\n\n```bash\n./gradlew :btrace-ext-cli:test\n```\n\n**Results:** All 28 tests passing ✓ (24 new + 4 existing PolicyFileTest)\n\n### Key Design Decisions\n\n- Used @TempDir for isolated test directories\n- Programmatic JAR creation avoids fixture file maintenance\n- Tests focus on dry-run mode to avoid actual network/filesystem operations\n- Error handling tests validate user-friendly error messages\n\n---\n\n## 4. V2 Protocol Integration Tests ⏸️\n\n### Problem Statement\n\nNo end-to-end test validates v2 binary protocol through full client-agent communication.\n\n### Status\n\n**Status:** ⏸️ **DEFERRED** (Strong unit test coverage exists)\n\n### Rationale for Deferral\n\nComprehensive unit tests already exist in:\n- `btrace-core/src/test/java/org/openjdk/btrace/core/comm/v2/BinaryProtocolTest.java`\n- `btrace-core/src/test/java/org/openjdk/btrace/core/comm/v2/BinaryProtocolEdgeCasesTest.java`\n- `btrace-core/src/test/java/org/openjdk/btrace/core/comm/v2/BinaryProtocolPerformanceTest.java`\n\nThese unit tests validate:\n- BigInteger/BigDecimal serialization\n- HistogramData serialization\n- NumberMapDataCommand with big numbers\n- GridDataCommand formatting\n- Protocol compression\n- All command types round-trip correctly\n\n### Recommendation\n\nIntegration tests would add marginal value given the comprehensive unit test coverage. If implemented in the future, they should focus on:\n- Protocol version negotiation under network failures\n- Large payload behavior in real network conditions\n- Protocol fallback from v2 to v1 when needed\n\n---\n\n## 5. Extension Concurrency Tests ⏸️\n\n### Problem Statement\n\nLimited testing of concurrent extension loading scenarios and thread-safety.\n\n### Status\n\n**Status:** ⏸️ **PENDING** (Basic coverage exists)\n\n### Existing Coverage\n\nBasic concurrency test exists:\n- `btrace-extension/src/test/java/org/openjdk/btrace/extension/ExtensionLoaderImplConcurrencyTest.java`\n\nTests single-threaded loading and basic scenarios.\n\n### Proposed Enhancements\n\nIf implemented, should add:\n\n1. **Concurrent same extension loading** - 100 threads load identical extension\n2. **Concurrent different extensions** - Multiple extensions loaded in parallel\n3. **Service lookup concurrency** - Service resolution during concurrent loads\n4. **Dependency resolution races** - Extensions with inter-dependencies\n5. **Reload scenarios** - Unload + reload race conditions\n6. **ClassLoader isolation** - Verify classloader boundaries under concurrency\n\n### Priority\n\n**LOW** - Basic thread-safety is validated, edge cases are rare in production usage.\n\n---\n\n## Summary\n\n### Completed Work\n\n**Tests Added:** 33 new tests across 3 test categories\n- Extension Lifecycle: +3 integration tests\n- Oneliner Runtime: +6 integration tests\n- Extension CLI: +24 unit tests\n\n**Files Created:**\n- 4 integration test BTrace scripts\n- 1 integration test class\n- 4 CLI unit test classes\n- 1 test utility class (TestExtensionBuilder)\n\n**Files Modified:**\n- 1 integration test class enhanced (BTraceFunctionalTests)\n- 1 build configuration updated (btrace-ext-cli/build.gradle)\n\n**Total Lines:** ~2,200 lines of test code\n\n### Test Execution Commands\n\n```bash\n# Extension lifecycle tests\n./gradlew :integration-tests:test --tests \"ExtensionLifecycleIntegrationTest\" -Pintegration\n\n# Oneliner runtime tests\n./gradlew :integration-tests:test --tests \"BTraceFunctionalTests.testOneliner*\" -Pintegration\n\n# Extension CLI tests\n./gradlew :btrace-ext-cli:test\n\n# All tests\n./gradlew test -Pintegration\n```\n\n### Success Metrics\n\n- ✅ **Coverage**: 3 of 5 testing gaps addressed (60%)\n- ✅ **Reliability**: All 39 tests pass consistently (0 flaky tests)\n- ✅ **Performance**: Tests complete within expected timeframes\n- ✅ **Maintenance**: Tests are self-documenting with clear names\n\n---\n\n## Future Work\n\n### Deferred Items\n\n1. **V2 Protocol Integration Tests** (HIGH priority if v2 protocol issues arise)\n   - Focus on network failure scenarios\n   - Protocol negotiation edge cases\n   - Fallback behavior validation\n\n2. **Extension Concurrency Enhancements** (LOW priority)\n   - Enhanced race condition testing\n   - Stress testing with many extensions\n   - Classloader isolation validation\n\n### Recommendations\n\nThe deferred items should be revisited if:\n- Protocol-related bugs are reported in production\n- Extension loading race conditions are observed\n- Performance issues indicate concurrency problems\n\nFor now, the existing unit test coverage provides adequate confidence in these areas.\n\n---\n\n## References\n\n- `integration-tests/src/test/java/tests/RuntimeTest.java` - Base test infrastructure\n- `btrace-core/src/test/java/org/openjdk/btrace/core/comm/v2/` - V2 protocol unit tests\n- `btrace-extension/src/test/java/` - Extension loading tests\n- `btrace-ext-cli/src/main/java/org/openjdk/btrace/extcli/` - CLI implementation\n"
  },
  {
    "path": "docs/releasing.md",
    "content": "# Releasing BTrace\n\n## Automated Release Process\n\nBTrace uses an automated release process via GitHub Actions. The release is triggered using the `scripts/release.sh` script.\n\n### Prerequisites\n\n1. **GitHub CLI**: Install and authenticate with `gh auth login`\n2. **Clean working directory**: Commit or stash any local changes\n3. **Correct branch**: Be on `develop` for major/minor releases, or `release/X.Y` for patch releases\n\n### Release Types\n\n| Type | When to Use | Example |\n|------|-------------|---------|\n| **major** | Breaking changes, major new features | 2.3.0-SNAPSHOT → 3.0.0 |\n| **minor** | New features, non-breaking changes | 2.3.0-SNAPSHOT → 2.3.0 |\n| **patch** | Bug fixes on release branch | 2.3.1-SNAPSHOT → 2.3.1 |\n\n### Running a Release\n\n```bash\n# Minor release from develop (most common)\n./scripts/release.sh minor\n\n# Major release from develop\n./scripts/release.sh major\n\n# Patch release from a release branch\n./scripts/release.sh patch release/2.3\n\n# Dry run (see what would happen without triggering)\nDRY_RUN=true ./scripts/release.sh minor\n```\n\n### What Happens During Release\n\nThe release workflow performs these steps:\n\n1. **Validation**: Verifies inputs, checks tag doesn't exist\n2. **Build & Test**: Runs full build and unit tests\n3. **Integration Tests**: Tests on JDK 8, 11, 17, 21\n4. **Prepare Release**: Creates/updates release branch, updates version, creates tag\n5. **Stage to Maven Central**: Uploads artifacts to staging (requires manual release)\n6. **⏸️ MANUAL CHECKPOINT**: You must release artifacts via Central Portal\n7. **Wait for Maven Central**: Polls until artifacts are available (30 min timeout)\n8. **Build Distributions**: Creates tar.gz, zip, deb, rpm packages\n9. **GitHub Release**: Creates release with artifacts and changelog\n10. **SDKMan Update**: Announces new version to SDKMan\n11. **JBang**: Automatic - uses Maven Central artifacts\n12. **Version Bumps**: Updates develop and release branch to next snapshots\n13. **Milestones**: Creates/closes milestone, associates merged PRs\n\n### Manual Release Step\n\nAfter step 5, the workflow pauses and waits for you to manually release the Maven artifacts:\n\n1. Go to [Central Portal Deployments](https://central.sonatype.com/publishing/deployments)\n2. Find the staged repository for BTrace\n3. **Review** the artifacts to ensure everything looks correct\n4. Click **Publish** to release to Maven Central\n5. The workflow will detect the release and continue automatically\n\nIf you don't want to proceed:\n- Simply let the workflow timeout (30 minutes), or\n- Cancel the workflow run\n- Drop the staging repository via Central Portal\n\nThis checkpoint allows you to verify the release before it becomes irreversible.\n\n### Branch Strategy\n\nBTrace uses trunk-based development with `develop` as the main branch:\n\n- **develop**: Main trunk - all development and releases start here\n- **release/X.Y**: Long-lived branches for patch releases (created automatically during major/minor releases)\n- **Tags**: `vX.Y.Z` format (e.g., `v2.3.0`) - the latest release is always identifiable via tags\n\n### Manual Verification (Optional)\n\nFor critical releases, you can trigger a dry run first:\n\n```bash\nDRY_RUN=true ./scripts/release.sh minor\n```\n\nOr use the GitHub Actions UI to trigger with `dry_run: true`.\n\n## Maven Central\n\nArtifacts are staged to Maven Central via the [Central Portal](https://central.sonatype.com/).\nThe workflow does **not** auto-release - you must manually publish from the Central Portal after reviewing the staged artifacts.\n\n### Staged Release Process\n\n1. Workflow uploads signed artifacts to a staging repository\n2. You review artifacts at [Central Portal Deployments](https://central.sonatype.com/publishing/deployments)\n3. Click \"Publish\" to release, or \"Drop\" to discard\n4. Once published, artifacts sync to Maven Central within ~10 minutes\n\n### Maven Coordinates\n\n```xml\n<dependency>\n    <groupId>io.btrace</groupId>\n    <artifactId>btrace-client</artifactId>\n    <version>VERSION</version>\n</dependency>\n```\n\nAvailable artifacts:\n- `io.btrace:btrace-agent`\n- `io.btrace:btrace-client`\n- `io.btrace:btrace-boot`\n\n### Credentials\n\nThe workflow uses these GitHub secrets:\n- `SONATYPE_USERNAME`: Central Portal user token username\n- `SONATYPE_PASSWORD`: Central Portal user token password\n- `GPG_SIGNING_KEY`: GPG private key for artifact signing\n- `GPG_SIGNING_PWD`: GPG key passphrase\n\nGenerate Central Portal tokens at: https://central.sonatype.com/account\n\n## SDKMan\n\nAfter the GitHub release is created, the workflow announces the new version to SDKMan.\nBTrace will be available via:\n\n```bash\nsdk install btrace\n```\n\nFor major releases, `sdkMajorRelease` is used; for minor/patch, `sdkMinorRelease` is used.\n\n## JBang\n\nJBang automatically picks up new versions from Maven Central. No manual action required.\nOnce Maven Central has the artifacts, users can run:\n\n```bash\njbang catalog add --name btraceio https://raw.githubusercontent.com/btraceio/jbang-catalog/main/jbang-catalog.json\njbang btrace@btraceio <PID> script.java\n```\n\nRelease checklist for JBang:\n- The release workflow updates `btraceio/jbang-catalog` automatically when `JBANG_CATALOG_PAT` is configured.\n- If the workflow cannot push, update `btrace.java` in `btraceio/jbang-catalog` to the new major/minor version.\n\n## Rollback Procedure\n\n### Before Maven Central release (reversible)\n\nIf the workflow is waiting for Maven Central and you want to abort:\n\n1. **Cancel the workflow** in GitHub Actions\n2. **Drop the staging repository** via [Central Portal](https://central.sonatype.com/publishing/deployments)\n3. **Delete the tag** (if created):\n   ```bash\n   git tag -d vX.Y.Z\n   git push origin :refs/tags/vX.Y.Z\n   ```\n4. **Reset release branch** if needed:\n   ```bash\n   git checkout release/X.Y\n   git reset --hard <previous-commit>\n   git push --force origin release/X.Y\n   ```\n\n### After Maven Central release (irreversible)\n\nOnce artifacts are released to Maven Central, they cannot be deleted. You can only:\n- Release a new patch version with fixes\n- Document the issue in release notes\n\nSimilarly, SDKMan announcements cannot be retracted.\n\n## Troubleshooting\n\n### Workflow fails during tests\n- Check test reports in workflow artifacts\n- Fix issues and re-run the release script\n\n### Wait for Maven Central times out\n- The workflow waits 30 minutes for you to release via Central Portal\n- If you missed it, manually complete the release:\n  1. Release artifacts via [Central Portal](https://central.sonatype.com/publishing/deployments)\n  2. Create GitHub release manually with artifacts from the workflow\n  3. Run SDKMan update: `./gradlew :btrace-dist:sdkMinorRelease`\n\n### Maven Central staging fails\n- Verify credentials are valid (regenerate tokens if needed)\n- Check signing key hasn't expired\n- Review Sonatype status: https://status.sonatype.com/\n\n### SDKMan update fails\n- Verify SDKMan API credentials\n- SDKMan updates can be retried manually via Gradle:\n  ```bash\n  # For minor/patch releases\n  ./gradlew :btrace-dist:sdkMinorRelease\n\n  # For major releases\n  ./gradlew :btrace-dist:sdkMajorRelease\n  ```\n"
  },
  {
    "path": "docs/samples/permissions.properties",
    "content": "# Minimal policy file example (simplified model)\nallowExtensions=btrace-statsd,my-metrics\ndenyExtensions=legacy-foo\nallowPrivileged=false\n"
  },
  {
    "path": "gradle/spotless.gradle",
    "content": "apply plugin: 'com.diffplug.spotless'\n\nspotless {\n    java {\n        target 'src/*/java/**/*.java'\n        // note: you can use an empty string for all the imports you didn't specify explicitly, and '\\\\#` prefix for static imports\n        importOrder('java', 'javax', 'org.openjdk.btrace', '', '\\\\#org.openjdk.btrace', '\\\\#')\n        removeUnusedImports()\n\n        googleJavaFormat()   // has its own section below\n\n        formatAnnotations()  // fixes formatting of type annotations, see below\n\n//        licenseHeader '/* (C) $YEAR */' // or licenseHeaderFile\n    }\n}\n\ntasks.register('formatCode') {\n    dependsOn 'spotlessApply'\n}\ncheck.configure {\n    dependsOn 'spotlessCheck'\n}"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd \"${APP_HOME:-./}\" > /dev/null && pwd -P ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "integration-tests/build.gradle",
    "content": "import java.nio.file.Files\nimport java.nio.file.Paths\n\napply plugin: 'java'\n\ndependencies {\n    implementation project(':btrace-compiler')\n    implementation project(':btrace-extensions:btrace-metrics')\n    testImplementation project(':btrace-client')\n    testImplementation project(':btrace-core')\n    testImplementation libs.testcontainers\n}\n\ncompileTestJava {\n    sourceCompatibility = 8\n    targetCompatibility = 8\n}\n\ntask buildEventsJar(type: Jar) {\n    inputs.files compileJava\n    from files(\"${project.buildDir}/classes/java/main\")\n    archiveBaseName = \"events\"\n    archiveVersion = \"\"\n    archiveClassifier = \"\"\n}\n\ntask compileTestProbes {\n    dependsOn compileTestJava, ':btrace-extensions:buildExtensionsApi', ':btrace-instr:jar', ':btrace-compiler:jar'\n    doLast {\n        def path = project(':integration-tests').sourceSets.main.runtimeClasspath\n\n        def loader = new URLClassLoader(path.collect { f -> f.toURL() } as URL[])\n        def compiler = loader.loadClass('org.openjdk.btrace.compiler.Compiler')\n        def rtCp = sourceSets.main.runtimeClasspath\n        // Ensure the BTrace extension API JAR(s) (with manifest attributes) are present on classpath\n        def extApiJars = []\n        rootProject.subprojects.each { sp ->\n            if (sp.plugins.hasPlugin('org.openjdk.btrace.extension')) {\n                try {\n                    def apiJar = sp.tasks.named('buildApiJar').get().archiveFile.get().asFile\n                    extApiJars << apiJar\n                } catch (Throwable ignored) { }\n            }\n        }\n        if (extApiJars.isEmpty()) {\n            logger.lifecycle(\"[integration-tests] No extension API JARs found. If you renamed an extension module, ensure it applies id 'org.openjdk.btrace.extension'.\")\n        } else {\n            rtCp = rtCp.plus(files(extApiJars))\n            logger.lifecycle(\"[integration-tests] Using extension API JARs: ${extApiJars}\")\n        }\n\n        def fullCp = rtCp.plus(files(buildDir.toPath().resolve(\"classes/java/test\"), buildDir.toPath().resolve(\"classes/java/java11_dummy\")))\n        def cpPath = fullCp.getAsPath()\n        def args = [\"-cp\", cpPath, \"-d\", buildDir.toPath().resolve(\"classes\").toString()]\n\n        def files = fileTree(dir: \"src/test/btrace\", include: '**/*.java', exclude: 'verifier/**/*.java').findAll {\n            it != null\n        }.collect { it }\n\n        args.addAll(files)\n\n        // Ensure BTrace compiler and its Verifier use the same classloader for resource lookups\n        // and have access to extension API manifest metadata\n        def prev = Thread.currentThread().contextClassLoader\n        try {\n            Thread.currentThread().contextClassLoader = loader\n            System.setProperty('btrace.allow.undeclared.services', 'true')\n            System.setProperty('java.class.path', cpPath)\n            compiler.main(args as String[])\n        } finally {\n            Thread.currentThread().contextClassLoader = prev\n            System.clearProperty('btrace.allow.undeclared.services')\n        }\n    }\n}\n\ntest {\n    onlyIf {\n        project.hasProperty(\"integration\")\n    }\n    dependsOn cleanTest, buildEventsJar, compileTestProbes,\n             ':btrace-dist:btraceJar',\n             ':btrace-dist:explodeExtensions', ':btrace-extensions:buildExtensionsApi'\n\n    testLogging.showStandardStreams = true\n\n    def dockerAvailable = false\n    if (project.hasProperty(\"integration\")) {\n        String dockerHost = System.getenv(\"DOCKER_HOST\")\n        try {\n            if (dockerHost == null || dockerHost.trim().isEmpty()) {\n                def defaultSocket = new File(\"/var/run/docker.sock\")\n                if (defaultSocket.exists()) {\n                    dockerHost = \"unix:///var/run/docker.sock\"\n                }\n                def hostOutput = new ByteArrayOutputStream()\n                def hostResult = exec {\n                    commandLine 'docker', 'context', 'inspect', '--format', '{{.Endpoints.docker.Host}}'\n                    ignoreExitValue true\n                    standardOutput = hostOutput\n                    errorOutput = hostOutput\n                }\n                def hostText = hostOutput.toString().trim()\n                if (hostResult.exitValue == 0 && !hostText.isEmpty()) {\n                    dockerHost = hostText\n                } else {\n                    logger.warn(\"[integration-tests] Docker context host not available: ${hostText}.\")\n                }\n            }\n\n            if (dockerHost != null && !dockerHost.trim().isEmpty()) {\n                def infoOutput = new ByteArrayOutputStream()\n                def infoResult = exec {\n                    commandLine 'docker', 'info', '--format', '{{.ServerVersion}}'\n                    ignoreExitValue true\n                    standardOutput = infoOutput\n                    errorOutput = infoOutput\n                    environment 'DOCKER_HOST', dockerHost\n                }\n                def infoText = infoOutput.toString().trim()\n                if (!(infoResult.exitValue == 0 && !infoText.isEmpty())) {\n                    logger.warn(\"[integration-tests] Docker not available (docker info returned: ${infoText}).\")\n                }\n            } else {\n                logger.warn(\"[integration-tests] Docker host not configured.\")\n            }\n        } catch (Exception e) {\n            logger.warn(\"[integration-tests] Docker not available (${e.getClass().getSimpleName()}: ${e.getMessage()}).\")\n        }\n        dockerAvailable = dockerHost != null && !dockerHost.trim().isEmpty()\n        if (!dockerAvailable) {\n            logger.warn(\"[integration-tests] Docker not available; skipping tests tagged 'docker'.\")\n        } else {\n            if (System.getenv(\"DOCKER_HOST\") == null || System.getenv(\"DOCKER_HOST\").trim().isEmpty()) {\n                environment 'DOCKER_HOST', dockerHost\n            }\n            if (dockerHost.startsWith(\"unix://\")) {\n                environment 'TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE', dockerHost.replace(\"unix://\", \"\")\n            }\n            systemProperty 'docker.host', dockerHost\n            if (dockerHost.startsWith(\"unix://\")) {\n                systemProperty 'testcontainers.docker.socket.override', dockerHost.replace(\"unix://\", \"\")\n                systemProperty 'testcontainers.dockerclient.strategy', 'org.testcontainers.dockerclient.UnixSocketClientProviderStrategy'\n            }\n            logger.lifecycle(\"[integration-tests] Using DOCKER_HOST=${dockerHost}\")\n        }\n        systemProperty 'btrace.docker.available', String.valueOf(dockerAvailable)\n        useJUnitPlatform {\n            if (!dockerAvailable) {\n                excludeTags 'docker'\n            }\n        }\n    }\n\n    def props = new Properties()\n    props.load(Files.newInputStream(Paths.get(System.getenv(\"JAVA_HOME\"), \"release\")))\n    def isJava8 = props.getProperty(\"JAVA_VERSION\")?.contains(\"1.8\")\n    if (isJava8) {\n        jvmArgs \"-Dproject.dir=${projectDir}\", \"-Dproject.version=${project.version}\", \"-Dbtrace.libs=${projectDir}/../btrace-dist/build/resources/main/v${project.version}/libs/\"\n    } else {\n        jvmArgs \"-Dproject.dir=${projectDir}\", \"-Dbtrace.libs=${projectDir}/../btrace-dist/build/resources/main/v${project.version}/libs/\", '-XX:+IgnoreUnrecognizedVMOptions', '--add-opens', 'java.base/jdk.internal.reflect=ALL-UNNAMED', '--add-exports', 'java.base/jdk.internal.reflect=ALL-UNNAMED', '--add-modules', 'jdk.attach', '--add-exports', 'jdk.attach/sun.tools.attach=ALL-UNNAMED', \"-Dproject.version=${project.version}\"\n    }\n    if (!isJava8) {\n        classpath = classpath.filter { it.name != 'tools.jar' }\n    }\n\n    // Canonical propagation: use Gradle project properties only (-P)\n    // -Pbtrace.debug=true will enable verbose logs in the tests (maps to btrace.test.debug)\n    // Any other -Pbtrace.* properties are forwarded verbatim to the test JVM and then to the traced app\n    project.properties.findAll { k, v -> k instanceof String && k.startsWith('btrace.') }.each { k, v ->\n        def key = (String) k\n        def val = String.valueOf(v)\n        systemProperty key, val\n        if (key == 'btrace.debug') {\n            systemProperty 'btrace.test.debug', val\n        }\n    }\n\n    // Expose CI flag to tests when passed as -PCI (or present in env)\n    // Treat presence of -PCI without value as 'true'\n    if (project.hasProperty('CI')) {\n        def ciVal = project.findProperty('CI')\n        def ci = (ciVal == null || ciVal.toString().trim().isEmpty()) ? 'true' : ciVal.toString()\n        systemProperty 'CI', ci\n    } else if (System.getenv('CI') != null) {\n        systemProperty 'CI', System.getenv('CI')\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/main/java/dummy/SimpleEvent.java",
    "content": "package dummy;\n\nimport jdk.jfr.Category;\nimport jdk.jfr.Enabled;\nimport jdk.jfr.Event;\nimport jdk.jfr.Label;\nimport jdk.jfr.Name;\nimport jdk.jfr.Registered;\n\n@Label(\"Simple Event\")\n@Registered\n@Enabled\n@Category(\"BTrace\")\n@Name(\"btrace.SimpleEvent\")\npublic class SimpleEvent extends Event {\n  @Label(\"value\")\n  private long value;\n\n  public SimpleEvent() {}\n\n  public long getValue() {\n    return value;\n  }\n\n  public void setValue(long value) {\n    this.value = value;\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/main/java/dummy/SimplePeriodicEvent.java",
    "content": "package dummy;\n\nimport jdk.jfr.Category;\nimport jdk.jfr.Enabled;\nimport jdk.jfr.Event;\nimport jdk.jfr.Label;\nimport jdk.jfr.Period;\n\n@Label(\"Simple periodic event\")\n@Period(\"everyChunk\")\n@Category(\"BTrace\")\n@Enabled\npublic class SimplePeriodicEvent extends Event {\n  @Label(\"value\")\n  private int value;\n\n  public SimplePeriodicEvent() {}\n\n  public void setValue(int value) {\n    this.value = value;\n  }\n\n  public int getValue() {\n    return value;\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/ExtensionLifecycleErrorTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Injected;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.utils.PrinterService;\n\nimport static org.openjdk.btrace.core.BTraceUtils.exit;\n\n@BTrace\npublic class ExtensionLifecycleErrorTest {\n  private static boolean exited = false;\n\n  @Injected private static PrinterService printer;\n\n  @OnMethod(clazz = \"resources.Main\", method = \"callB\")\n  public static void onCallB() {\n    printer.println(\"LIFECYCLE: extension method called\");\n    if (!exited) {\n      exited = true;\n      printer.println(\"Triggering error exit\");\n      // Exit with error code to simulate abnormal termination\n      exit(1);\n    }\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/ExtensionLifecycleFullTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Injected;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.utils.PrinterService;\n\nimport static org.openjdk.btrace.core.BTraceUtils.exit;\n\n@BTrace\npublic class ExtensionLifecycleFullTest {\n  private static boolean exited = false;\n\n  @Injected private static PrinterService printer;\n\n  @OnMethod(clazz = \"resources.Main\", method = \"callB\")\n  public static void onCallB() {\n    printer.println(\"LIFECYCLE: extension method called\");\n    if (!exited) {\n      exited = true;\n      exit();\n    }\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/ExtensionLifecycleMultipleTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Injected;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.metrics.MetricsService;\nimport org.openjdk.btrace.utils.PrinterService;\n\nimport static org.openjdk.btrace.core.BTraceUtils.exit;\n\n@BTrace\npublic class ExtensionLifecycleMultipleTest {\n  private static boolean exited = false;\n\n  @Injected private static PrinterService printer;\n  @Injected private static MetricsService metrics;\n\n  @OnMethod(clazz = \"resources.Main\", method = \"callB\")\n  public static void onCallB() {\n    printer.println(\"LIFECYCLE: printer extension called\");\n    metrics.histogram(\"test\").record(1);\n    printer.println(\"LIFECYCLE: metrics extension called\");\n    if (!exited) {\n      exited = true;\n      exit();\n    }\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/ExtensionLifecycleTest.java",
    "content": "package btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Injected;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.utils.PrinterService;\n\nimport static org.openjdk.btrace.core.BTraceUtils.exit;\n\n@BTrace\npublic class ExtensionLifecycleTest {\n  private static boolean exited = false;\n\n  @Injected private static PrinterService printer;\n\n  @OnMethod(clazz = \"resources.Main\", method = \"callB\")\n  public static void onCallB() {\n    printer.println(\"extension callB\");\n    if (!exited) {\n      exited = true;\n      exit();\n    }\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/JfrTest.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.jfr.JfrEvent;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\nimport static org.openjdk.btrace.core.BTraceUtils.Jfr.*;\n\n@BTrace\npublic class JfrTest {\n    @Event(name=\"custom\", label=\"Custom Event\", fields=@Event.Field(type = Event.FieldType.STRING, name = \"thiz\"))\n    private static JfrEvent.Factory custom;\n\n    private static int counter = 0;\n\n    @PeriodicEvent(name=\"periodic\", label=\"Periodic\", description=\"Periodic Event\", period=\"1 s\", fields = @Event.Field(type = Event.FieldType.INT, name = \"count\"))\n    public static void periodic(JfrEvent event) {\n        if (shouldCommit(event)) {\n            setEventField(event, \"count\", counter++);\n            commit(event);\n        }\n    }\n\n    @OnMethod(clazz = \"resources.Main\", method = \"callA\")\n    public static void noargs(@Self Object self) {\n        println(\"Main.callA\");\n        JfrEvent event = prepareEvent(custom);\n        setEventField(event, \"thiz\", str(self));\n        commit(event);\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/MetricsTest.java",
    "content": "/*\n * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Duration;\nimport org.openjdk.btrace.core.annotations.Injected;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.OnTimer;\nimport org.openjdk.btrace.metrics.MetricsService;\nimport org.openjdk.btrace.metrics.histogram.HistogramConfig;\nimport org.openjdk.btrace.metrics.histogram.HistogramMetric;\nimport org.openjdk.btrace.metrics.histogram.HistogramSnapshot;\nimport org.openjdk.btrace.metrics.stats.StatsMetric;\nimport org.openjdk.btrace.metrics.stats.StatsSnapshot;\n\nimport static org.openjdk.btrace.core.BTraceUtils.println;\n\n/**\n * Test HDR histogram metrics integration.\n */\n@BTrace\npublic class MetricsTest {\n\n  @Injected\n  private static MetricsService metrics;\n\n  private static HistogramMetric histogram;\n  private static StatsMetric stats;\n\n  static {\n    println(\"=== HDR Histogram Metrics Test ===\");\n  }\n\n  @OnMethod(clazz = \"resources.Main\", method = \"callB\")\n  public static void onEntry() {\n    println(\"On call B entry\");\n    if (histogram == null) {\n      histogram = metrics.histogramMicros(\"main.callB\");\n      stats = metrics.stats(\"main.callB.stats\");\n    }\n  }\n\n  @OnMethod(clazz = \"resources.Main\", method = \"callB\", location = @Location(Kind.RETURN))\n  public static void onReturn(@Duration long durationNanos) {\n    println(\"On return\");\n    if (histogram != null) {\n      long durationMicros = durationNanos / 1000;\n      histogram.record(durationMicros);\n      stats.record(durationMicros);\n    }\n  }\n\n  @OnTimer(100)\n  public static void onTimer() {\n    if (histogram != null) {\n      HistogramSnapshot h = histogram.snapshot();\n      StatsSnapshot s = stats.snapshot();\n\n      println(\"=== Metrics Report ===\");\n      println(\"Count: \" + s.count());\n      println(\"Mean: \" + s.mean() + \" μs\");\n      println(\"Min: \" + s.min() + \" μs\");\n      println(\"Max: \" + s.max() + \" μs\");\n      println(\"P50: \" + h.p50() + \" μs\");\n      println(\"P95: \" + h.p95() + \" μs\");\n      println(\"P99: \" + h.p99() + \" μs\");\n      println(\"======================\");\n    }\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/OSMBeanTest.java",
    "content": "/*\n * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnTimer;\nimport org.openjdk.btrace.core.annotations.TLS;\n\nimport java.util.Deque;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * @author Jaroslav Bachorik\n */\n@BTrace(unsafe = true)\npublic class OSMBeanTest {\n    @TLS\n    public static Deque<Long> entryTimes = BTraceUtils.Collections.newDeque();\n\n    @OnTimer(200)\n    public static void tester() {\n        try {\n            double la = Sys.VM.systemLoadAverage();\n            long t = Sys.VM.processCPUTime();\n            BTraceUtils.push(entryTimes, t);\n            println(la + \" # \" + t);\n        } catch (Throwable e) {\n            println(\"FAILED\");\n            println(e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/OnExitTest.java",
    "content": "/*\n * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnExit;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class OnExitTest {\n    @OnExit\n    public static void onexit(int code) {\n        dump(\"onexit\");\n    }\n\n    private static void dump(String s) {\n        println(s);\n    }\n}"
  },
  {
    "path": "integration-tests/src/test/btrace/OnMethodLevelTest.java",
    "content": "/*\n * Copyright (c) 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.*;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\nimport static org.openjdk.btrace.core.BTraceUtils.Reflective.*;\nimport org.openjdk.btrace.core.annotations.Export;\n\n/**\n *\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class OnMethodLevelTest {\n    @TLS\n    private static int tls = 10;\n\n    @Export\n    private static long ex = 1;\n\n    private static String var = \"none\";\n\n    @OnMethod(clazz = \"resources.Main\", method = \"callA\", enableAt = @Level(\"100\"))\n    public static void noargs(@Self Object self) {\n        tls++;\n        ex += 1;\n        dump(var + \" [this, noargs]\");\n        dump(\"{\" + get(\"id\", self) + \"}\");\n        var = \"A\";\n    }\n\n    @OnMethod(clazz = \"resources.Main\", method = \"callB\", enableAt = @Level(\"150\"), location = @Location(Kind.RETURN))\n    public static void args(@Self Object self, int i, String s, @Duration long duration) {\n        tls -= 1;\n        ex--;\n        dump(var + \" [this, args]\");\n        var = \"B\";\n    }\n\n    private static void dump(String s) {\n        println(s);\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/OnMethodReturnTest.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.types.AnyType;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class OnMethodReturnTest {\n    @OnMethod(clazz = \"resources.Main\", method = \"/call.*/\", location = @Location(Kind.RETURN))\n    public static void noargs(@Self Object self, @Return AnyType ret) {\n        if (BTraceUtils.instanceOf(ret, \"void\")) {\n            println(\"[this, anytype(void)]\");\n        } else {\n            println(\"[this, \" + ret + \"]\");\n        }\n    }\n\n    @OnMethod(clazz = \"resources.Main\", method = \"/call.*/\", location = @Location(Kind.RETURN))\n    public static void noargs_void(@Self Object self, @Return Void ret) {\n        println(\"[this, void]\");\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/OnMethodSubclassTest.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.ProbeMethodName;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class OnMethodSubclassTest {\n    @OnMethod(clazz = \"+resources.TestPrinter\", method = \"print\")\n    public static void onStartWork(@Self Object self, @ProbeMethodName String pmn) {\n        println(pmn + \":\" + str(classOf(self)));\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/OnMethodTest.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.types.AnyType;\nimport org.openjdk.btrace.core.BTraceUtils;\nimport org.openjdk.btrace.core.annotations.Export;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\nimport static org.openjdk.btrace.core.BTraceUtils.Reflective.*;\n\nimport dummy.SimplePeriodicEvent;\nimport dummy.SimpleEvent;\n\n/**\n *\n * @author Jaroslav Bachorik\n */\n@BTrace(trusted = false)\npublic class OnMethodTest {\n    @TLS\n    private static int tls = 10;\n\n    @Export\n    private static long ex = 1;\n\n    private static String var = \"none\";\n\n    @OnMethod(clazz = \"resources.Main\", method = \"callA\")\n    public static void noargs(@Self Object self) {\n        tls++;\n        ex += 1;\n        dump(var + \" [this, noargs]\");\n        dump(\"{\" + get(\"id\", self) + \"}\");\n        var = \"A\";\n        println(\"prop: \" + property(\"btrace.test\"));\n    }\n\n    @OnMethod(clazz = \"resources.Main\", method = \"callB\")\n    public static void args(@Self Object self, int i, String s) {\n        tls -= 1;\n        ex--;\n        dump(var + \" [this, args]\");\n        var = \"B\";\n        println(\"prop: \" + property(\"btrace.test\"));\n    }\n\n    @OnMethod(clazz = \"+resources.Main\", method = \"startWork\")\n    public static void onSubtype() {\n        println(\"subtype\");\n    }\n\n    @OnMethod(clazz = \"resources.Main\", method = \"/^call.*/\",\n              location = @Location(value = Kind.FIELD_GET, clazz = \"resources.Main\", field = \"/^s?[fF]ield$/\"))\n    public static void fieldGet(@TargetMethodOrField(fqn = true) String fldName) {\n        println(\"fieldGet: \" + fldName);\n    }\n\n    @OnMethod(clazz = \"resources.Main\", method = \"/^call.*/\",\n        location = @Location(value = Kind.FIELD_SET, clazz = \"resources.Main\", field = \"/^s?[fF]ield$/\"))\n    public static void fieldSet(@TargetMethodOrField(fqn = true) String fldName) {\n        println(\"fieldSet: \" + fldName);\n    }\n\n    @OnTimer(500)\n    public static void doRecurrent() {\n        // Print only once to avoid unbounded output in unattended mode\n        // which can cause CI to wait for excessive line counts.\n        if (timerHits == 0) {\n            println(10);\n        }\n        timerHits++;\n    }\n\n    private static int timerHits = 0;\n\n    private static void dump(String s) {\n        println(s);\n        println(\"heap:\" + Sys.Memory.heapUsage());\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/OnProbeTest.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnProbe;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class OnProbeTest {\n    @OnProbe(name = \"noargs\", namespace = \"org.openjdk.btrace\")\n    public static void noargs(@Self Object self) {\n        println(\"[this, noargs]\");\n    }\n\n    @OnProbe(name = \"withargs\", namespace = \"org.openjdk.btrace\")\n    public static void args(@Self Object self, int i, String s) {\n        dump(\"[this, args]\");\n    }\n\n    private static void dump(String s) {\n        println(s);\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/OnTimerArgTest.java",
    "content": "/*\n * Copyright (c) 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnTimer;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class OnTimerArgTest {\n    static {\n        println(\"vm version \" + Sys.VM.vmVersion());\n        println(\"vm starttime \" + Sys.VM.vmStartTime());\n    }\n\n    @OnTimer(from = \"${timer}\")\n    public static void ontimer() {\n        dump(\"timer\");\n    }\n\n    private static void dump(String s) {\n        println(s);\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/OnTimerTest.java",
    "content": "/*\n * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnTimer;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class OnTimerTest {\n    static {\n        println(\"vm version \" + Sys.VM.vmVersion());\n        println(\"vm starttime \" + Sys.VM.vmStartTime());\n    }\n\n    @OnTimer(500)\n    public static void ontimer() {\n        dump(\"timer\");\n    }\n\n    private static void dump(String s) {\n        println(s);\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/PerfCounterTest.java",
    "content": "/*\n * Copyright (c) 2019, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Export;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * @author Jaroslav Bachorik\n */\n@BTrace\npublic class PerfCounterTest {\n    @Export\n    private static int counter;\n\n    @OnMethod(clazz = \"resources.Main\", method = \"callA\")\n    public static void trace() {\n        println(\"matching probe\");\n        counter++;\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/ProbeArgsTest.java",
    "content": "/*\n * Copyright (c) 2018, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage btrace;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n/**\n * @author Jaroslav Bachorik\n */\n@BTrace(trusted = true)\npublic class ProbeArgsTest {\n    static {\n        println(\"arg#=\" + Sys.$length());\n        for (int i = 0; i < Sys.$length(); i++) {\n            println(\"#\" + i + \"=\" + Sys.$(i));\n        }\n        println(\"arg1=\" + Sys.$(\"arg1\"));\n        println(\"arg2=\" + Sys.$(\"arg2\"));\n        println(\"arg3=\" + Sys.$(\"arg3\"));\n    }\n\n    @OnMethod(clazz = \"${clzParam}\", method = \"${mthdParam}\")\n    public static void trace() {\n        println(\"matching probe\");\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/ThreadStart.java",
    "content": "/*\n * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage traces;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\n@BTrace\npublic class ThreadStart {\n    @OnMethod(\n            clazz = \"java.lang.Thread\",\n            method = \"start\"\n    )\n    public static void onnewThread(@Self Thread t) {\n        println(\"starting \" + Threads.name(t));\n    }\n}"
  },
  {
    "path": "integration-tests/src/test/btrace/TraceAllTest.java",
    "content": "/*\n * Copyright (c) 2024, Jaroslav Bachorik <j.bachorik@btrace.io>.\n * All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Copyright owner designates\n * this particular file as subject to the \"Classpath\" exception as provided\n * by the owner in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n\npackage traces;\n\nimport org.openjdk.btrace.core.annotations.*;\nimport org.openjdk.btrace.core.BTraceUtils;\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n *\n * @author Jaroslav Bachorik\n */\n@BTrace(trusted = false)\npublic class TraceAllTest {\n\n    private static final AtomicLong hitCnt = BTraceUtils.newAtomicLong(0);\n\n    @OnMethod(clazz = \"/.*/\")\n    public static void doall(@ProbeMethodName(fqn = true) String pmn) {\n        BTraceUtils.getAndIncrement(hitCnt);\n//        BTraceUtils.println(\"invoked: \" + pmn);\n    }\n\n    @OnTimer(500)\n    public static void doRecurrent() {\n        long cnt = BTraceUtils.get(hitCnt);\n        if (cnt > 0) {\n            println(\"[invocations=\" + cnt + \"]\");\n        }\n    }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/issues/BTRACE400.java",
    "content": "package traces.issues;\n\nimport static org.openjdk.btrace.core.BTraceUtils.*;\n\nimport org.openjdk.btrace.core.annotations.BTrace;\nimport org.openjdk.btrace.core.annotations.Kind;\nimport org.openjdk.btrace.core.annotations.Location;\nimport org.openjdk.btrace.core.annotations.OnMethod;\nimport org.openjdk.btrace.core.annotations.Self;\n\n/** @author Jaroslav Bachorik */\n@BTrace\npublic class BTRACE400 {\n  @OnMethod(clazz = \"/.*\\\\.Main/\", method = \"callA\", location = @Location(value = Kind.RETURN))\n  public static void tracker(@Self Object x) {\n    println(str(field(\"resources.Main\", \"id\")));\n    println(str(probeClass()));\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/btrace/org.openjdk.btrace.xml",
    "content": "<!--\n * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the Classpath exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n-->\n<btrace-probes namespace=\"org.openjdk.btrace\">\n    <probe name=\"noargs\">\n        <map>\n            <clazz>//resources\\..*//</clazz>\n            <method>callA</method>\n        </map>\n    </probe>\n    <probe name=\"withargs\">\n        <map>\n            <clazz>resources.Main</clazz>\n            <method>callB</method>\n        </map>\n    </probe>\n</btrace-probes>\n"
  },
  {
    "path": "integration-tests/src/test/java/resources/Main.java",
    "content": "/*\n * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage resources;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic class Main extends TestApp {\n  private String id = \"xxx\";\n  private String field;\n  private static String sField;\n\n  public static void main(String[] args) throws Exception {\n    Main i = new Main();\n    i.start();\n  }\n\n  @Override\n  protected void startWork() {\n    while (!Thread.currentThread().isInterrupted()) {\n      callA();\n      try {\n        Thread.sleep(200);\n      } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n      }\n    }\n  }\n\n  private void callA() {\n    field = \"AAA\";\n    sField = \"BBB\";print(\"i=\" + callB(1, \"Hello World\"));\n  }\n\n  private int callB(int i, String s) {\n    print(\"[\" + i + \"] = \" + s + \", field = \" + field + \", sField = \" + sField);\n    return i + 1;\n  }\n\n  @Override\n  public void print(String msg) {\n    System.out.println(msg);\n    System.out.flush();\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/java/resources/TestApp.java",
    "content": "/*\n * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage resources;\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.nio.charset.StandardCharsets;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic abstract class TestApp implements TestPrinter {\n  public final void start() throws Exception {\n    Thread t =\n        new Thread(\n            new Runnable() {\n              @Override\n              public void run() {\n                startWork();\n              }\n            },\n            \"Worker Thread\");\n    System.out.println(\"ready:\" + getPID());\n    System.out.flush();\n    t.setDaemon(true);\n    t.start();\n\n    do {\n      String resp =\n          new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)).readLine();\n      System.out.println(\"Received \" + resp + \" - \" + \"done\".contains(resp));\n      if (\"done\".contains(resp)) {\n        System.out.flush();\n        System.out.println(System.currentTimeMillis() + \":  Interrupting the worker thread\");\n        t.interrupt();\n        System.out.println(\n            System.currentTimeMillis() + \": Waiting for the worker thread to finish\");\n        t.join(1000);\n        if (t.isAlive()) {\n          Thread.dumpStack();\n          throw new RuntimeException(\"Dangling worker thread\");\n        }\n        System.out.println(System.currentTimeMillis() + \": Worker thread finished\");\n        break;\n      }\n    } while (true);\n  }\n\n  private static long getPID() {\n    String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();\n    return Long.parseLong(processName.split(\"@\")[0]);\n  }\n\n  /** The work here should be done repeatedly until the thread gets interrupted */\n  protected abstract void startWork();\n}\n"
  },
  {
    "path": "integration-tests/src/test/java/resources/TestPrinter.java",
    "content": "/*\n * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage resources;\n\n/**\n * @author Jaroslav Bachorik\n */\npublic interface TestPrinter {\n  void print(String msg);\n}\n"
  },
  {
    "path": "integration-tests/src/test/java/resources/ThreadSpawner.java",
    "content": "package resources;\n\npublic class ThreadSpawner extends TestApp {\n    public static void main(String[] args) throws Exception {\n        ThreadSpawner i = new ThreadSpawner();\n        i.start();\n    }\n    @Override\n    protected void startWork() {\n        while (!Thread.currentThread().isInterrupted()) {\n            try {\n                spawnThread();\n                Thread.sleep(200);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        }\n    }\n\n    private void spawnThread() throws InterruptedException {\n        Thread t = new Thread( () -> print(\"thread started\"));\n        t.setName(\"testThread\");\n        t.start();\n        t.join();\n    }\n\n    @Override\n    public void print(String msg) {\n        System.out.println(msg);\n        System.out.flush();\n    }\n}"
  },
  {
    "path": "integration-tests/src/test/java/tests/BTraceFunctionalTests.java",
    "content": "/*\n * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\n\npackage tests;\n\nimport jdk.jfr.EventType;\nimport jdk.jfr.consumer.RecordedEvent;\nimport jdk.jfr.consumer.RecordingFile;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.DisplayName;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\nimport org.openjdk.btrace.client.Client;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.DisconnectCommand;\nimport org.openjdk.btrace.core.comm.StatusCommand;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.junit.jupiter.api.Assumptions.assumeFalse;\n\n/**\n * A set of end-to-end functional tests.\n *\n * <p>The test simulates a user submitting a BTrace script to the target application and asserts\n * that no exceptions are thrown, JVM keeps on running and BTrace generates the anticipated output.\n *\n * @author Jaroslav Bachorik\n */\npublic class BTraceFunctionalTests extends RuntimeTest {\n  @BeforeAll\n  public static void setup() throws Exception {\n    classSetup();\n  }\n\n  @BeforeEach\n  @Override\n  public void reset() {\n    super.reset();\n  }\n\n  @Test\n  public void testOSMBean() throws Exception {\n    isUnsafe = true;\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/OSMBeanTest.java\",\n        2,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n          }\n        });\n  }\n\n  @Test\n  public void testOnProbe() throws Exception {\n    if (Files.exists(Paths.get(javaHome, \"jre\"))) {\n      testDynamic(\n          \"resources.Main\",\n          \"btrace/OnProbeTest.java\",\n          5,\n          new ResultValidator() {\n            @Override\n            public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n              assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n              assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n              assertTrue(stdout.contains(\"[this, noargs]\"));\n              assertTrue(stdout.contains(\"[this, args]\"));\n            }\n          });\n    } else {\n      System.err.println(\"XML libraries not available. Skipping @OnProbe tests\");\n    }\n  }\n\n  @Test\n  public void testOnTimer() throws Exception {\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/OnTimerTest.java\",\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"vm version\"));\n            assertTrue(stdout.contains(\"vm starttime\"));\n            assertTrue(stdout.contains(\"timer\"));\n          }\n        });\n  }\n\n  @Test\n  public void testOnTimerArg() throws Exception {\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/OnTimerArgTest.java\",\n        new String[] {\"timer=500\"},\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"vm version\"));\n            assertTrue(stdout.contains(\"vm starttime\"));\n            assertTrue(stdout.contains(\"timer\"));\n          }\n        });\n  }\n\n  @Test\n  public void testOnExit() throws Exception {\n    timeout = 3500;\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/OnExitTest.java\",\n        5,\n        (stdout, stderr, retcode, jfrFile) -> {\n          assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n          assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n          assertTrue(stdout.contains(\"onexit\"));\n        });\n  }\n\n  @Test\n  public void testOnMethod() throws Exception {\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/OnMethodTest.java\",\n        14,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"[this, noargs]\"));\n            assertTrue(stdout.contains(\"[this, args]\"));\n            assertTrue(stdout.contains(\"{xxx}\"));\n            assertTrue(stdout.contains(\"heap:init\"));\n            assertTrue(stdout.contains(\"prop: test\"));\n            assertTrue(stdout.contains(\"fieldSet: field java.lang.String resources.Main#field\"));\n            assertTrue(stdout.contains(\"fieldSet: static field java.lang.String resources.Main#sField\"));\n            assertTrue(stdout.contains(\"fieldGet: field java.lang.String resources.Main#field\"));\n            assertTrue(stdout.contains(\"fieldGet: static field java.lang.String resources.Main#sField\"));\n          }\n        });\n  }\n\n  @Test\n  public void testOnelinerRuntime() throws Exception {\n    dumpOneliner = Boolean.getBoolean(\"btrace.oneliner.dump\");\n    dumpVerifierErrors = Boolean.getBoolean(\"btrace.verifier.dump\");\n    String oneLiner = \"resources.Main::callB @entry { print method, args }\";\n    testDynamicOneliner(\n        \"resources.Main\",\n        oneLiner,\n        30,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"callB\"), \"Expected oneliner output\");\n            assertTrue(stdout.contains(\"Hello World\"), \"Expected oneliner args output\");\n          }\n        });\n  }\n\n  @Test\n  public void testExtensionLifecycleClose() throws Exception {\n    attachDelayMs = 500;\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/ExtensionLifecycleTest.java\",\n        new String[] {\"extensionCloseTest=true\"},\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"extension close: btrace-utils\"));\n          }\n        });\n  }\n\n  @Test\n  public void testTraceAll() throws Exception {\n      String testJavaHome = System.getenv().get(\"TEST_JAVA_HOME\");\n      if (testJavaHome == null) testJavaHome = System.getenv().get(\"JAVA_TEST_HOME\");\n      if (testJavaHome == null) {\n          testJavaHome = System.getenv(\"JAVA_HOME\");\n          if (testJavaHome == null) {\n              testJavaHome = System.getProperty(\"java.home\");\n          }\n      }\n\n      assumeFalse(testJavaHome == null);\n\n      Properties releaseProps = new Properties();\n      releaseProps.load(\n              Files.newInputStream(new File(testJavaHome + File.separator + \"release\").toPath()));\n      String rtVersion = releaseProps.getProperty(\"JAVA_VERSION\").replace(\"\\\"\", \"\");\n      if (!isVersionSafeForTraceAll(rtVersion)) {\n          System.err.println(\"Skipping test for JDK \" + rtVersion);\n          return;\n      }\n      testStartup(\n        \"resources.Main\",\n        \"traces/TraceAllTest.class\",\n        null,\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr: \" + stderr);\n            assertTrue(stdout.contains(\"[invocations=\"));\n          }\n        });\n  }\n\n  @Test\n  public void testOnMethodLevel() throws Exception {\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/OnMethodLevelTest.java\",\n        new String[] {\"level=200\"},\n        5,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"[this, noargs]\"));\n            assertTrue(stdout.contains(\"[this, args]\"));\n            assertTrue(stdout.contains(\"{xxx}\"));\n          }\n        });\n  }\n\n  @Test\n  public void testOnMethodTrackRetransform() throws Exception {\n    trackRetransforms = true;\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/OnMethodTest.java\",\n        2,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"Going to retransform class\"));\n          }\n        });\n  }\n\n  @Test\n  public void testOnMethodReturn() throws Exception {\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/OnMethodReturnTest.java\",\n        5,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"[this, anytype(void)]\"));\n            assertTrue(stdout.contains(\"[this, void]\"));\n            assertTrue(stdout.contains(\"[this, 2]\"));\n          }\n        });\n  }\n\n  @Test\n  public void testOnMethodSubclass() throws Exception {\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/OnMethodSubclassTest.java\",\n        5,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"print:class resources.Main\"));\n          }\n        });\n  }\n\n  @Test\n  public void testProbeArgs() throws Exception {\n//    debugBTrace = true;\n//    debugTestApp = true;\n    isUnsafe = true;\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/ProbeArgsTest.java\",\n        new String[] {\"arg1\", \"arg2=val2\"},\n        5,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"arg#=2\"));\n            assertTrue(stdout.contains(\"arg1=\"));\n            assertTrue(stdout.contains(\"arg2=val2\"));\n            assertFalse(stdout.contains(\"matching probe\"));\n          }\n        });\n  }\n\n  @Test\n  public void testPerfCounter() throws Exception {\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/PerfCounterTest.java\",\n        5,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"matching probe\"));\n          }\n        });\n  }\n\n  @Test\n  public void testReflection() throws Exception {\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/issues/BTRACE400.java\",\n        5,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"private java.lang.String resources.Main.id\"));\n            assertTrue(stdout.contains(\"class resources.Main\"));\n          }\n        });\n  }\n\n  @Test\n  public void testJfr() throws Exception {\n    String rtVersion = System.getProperty(\"java.runtime.version\", \"\");\n    String testJavaHome = System.getenv().get(\"TEST_JAVA_HOME\");\n    if (testJavaHome == null) testJavaHome = System.getenv().get(\"JAVA_TEST_HOME\");\n    if (testJavaHome != null) {\n      Properties releaseProps = new Properties();\n      releaseProps.load(\n          Files.newInputStream(new File(testJavaHome + File.separator + \"release\").toPath()));\n      rtVersion = releaseProps.getProperty(\"JAVA_VERSION\").replace(\"\\\"\", \"\");\n    }\n    if (!isVersionSafeForJfr(rtVersion)) {\n      // skip the test for 8.0.* because of missing support\n      // skip all non-LTS versions (except the last one)\n      // skip the test for JDK 11 since the latest version 11.0.9 and newer ends in SISGSEGV\n      System.err.println(\"Skipping test for JDK \" + rtVersion);\n      return;\n    }\n    testWithJfr(\n        \"resources.Main\",\n        \"btrace/JfrTest.java\",\n        30,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertNotNull(jfrFile);\n            try {\n              RecordingFile f = new RecordingFile(Paths.get(jfrFile));\n              boolean hasPeriodicType = false,\n                  hasPeriodicValue = false,\n                  hasCustomType = false,\n                  hasCustomValue = false;\n              for (EventType et : f.readEventTypes()) {\n                if (et.getName().equals(\"periodic\")) {\n                  hasPeriodicType = true;\n                } else if (et.getName().equals(\"custom\")) {\n                  hasCustomType = true;\n                }\n                if (hasPeriodicType && hasCustomType) {\n                  while (f.hasMoreEvents()) {\n                    RecordedEvent e = f.readEvent();\n                    if (e.getEventType().getName().equals(\"periodic\")) {\n                      hasPeriodicValue = true;\n                    } else if (e.getEventType().getName().equals(\"custom\")) {\n                      hasCustomValue = true;\n                    }\n                    if (hasPeriodicValue && hasCustomValue) {\n                      return;\n                    }\n                  }\n                  break;\n                }\n              }\n              fail(\n                  \"periodic type ok: \"\n                      + hasPeriodicType\n                      + \", periodic value ok: \"\n                      + hasPeriodicValue\n                      + \", custom type ok: \"\n                      + hasCustomType\n                      + \", custom value ok: \"\n                      + hasCustomValue);\n            } catch (IOException e) {\n              throw new RuntimeException(e);\n            }\n          }\n        });\n  }\n\n  @Test\n  public void testOnMethodUnattended() throws Exception {\n    TestApp testApp = launchTestApp(\"resources.Main\");\n    File traceFile = locateTrace(\"btrace/OnMethodTest.java\");\n\n    String pid = String.valueOf(testApp.getPid());\n    String host = \"localhost\";\n    Client client = createClientForTests(traceFile.getParentFile().getAbsolutePath());\n    client.attach(pid, null, getEventsClassPath());\n    byte[] code = client.compile(traceFile.getAbsolutePath(), getEventsClassPath());\n    assertNotNull(code, \"BTrace compilation failed\");\n\n    CompletableFuture<String> probeIdFuture = new CompletableFuture<>();\n    ExecutorService executor = Executors.newSingleThreadExecutor();\n    Future<?> submitFuture =\n        executor.submit(\n            () -> {\n              try {\n                client.submit(\n                    host,\n                    traceFile.getName(),\n                    code,\n                    new String[0],\n                    cmd -> {\n                      if (cmd.getType() == Command.STATUS) {\n                        StatusCommand status = (StatusCommand) cmd;\n                        if (status.getFlag() == StatusCommand.STATUS_FLAG && status.isSuccess()) {\n                          try {\n                            client.sendDisconnect();\n                          } catch (IOException e) {\n                            probeIdFuture.completeExceptionally(e);\n                          }\n                        } else if (!status.isSuccess()) {\n                          probeIdFuture.completeExceptionally(\n                              new IllegalStateException(\"Probe startup failed\"));\n                        }\n                      } else if (cmd.getType() == Command.DISCONNECT) {\n                        DisconnectCommand disconnect = (DisconnectCommand) cmd;\n                        probeIdFuture.complete(disconnect.getProbeId());\n                      }\n                    });\n              } catch (IOException e) {\n                if (!probeIdFuture.isDone()) {\n                  probeIdFuture.completeExceptionally(e);\n                }\n              }\n            });\n\n    String probeId = probeIdFuture.get(15, TimeUnit.SECONDS);\n    client.close();\n    try {\n      submitFuture.get(5, TimeUnit.SECONDS);\n    } catch (Exception ignore) {\n      // best effort; disconnect closes the socket and may surface as a submit error\n    } finally {\n      executor.shutdownNow();\n    }\n\n    List<String> probes = listProbesWithProtocol(host);\n    long matches =\n        probes.stream()\n            .filter(p -> extractProbeClassName(p).endsWith(\"OnMethodTest\"))\n            .count();\n    assertEquals(1, matches, \"expected exactly one OnMethodTest probe listed by -lp\");\n    assertTrue(\n        probes.stream().anyMatch(p -> p.startsWith(probeId + \" \")),\n        \"probe id not present in -lp output\");\n  }\n\n  private static String extractProbeClassName(String probeEntry) {\n    int lb = probeEntry.indexOf('[');\n    int rb = probeEntry.indexOf(']');\n    if (lb > -1 && rb > lb) {\n      return probeEntry.substring(lb + 1, rb).trim();\n    }\n    return \"\";\n  }\n\n    @ParameterizedTest(name = \"testThreadStart: dynamic={0}\")\n    @ValueSource(booleans = {true, false})\n    public void testThreadStart(boolean dynamic) throws Exception {\n        if (dynamic) {\n            testDynamic(\n                    \"resources.ThreadSpawner\",\n                    \"traces/ThreadStart.class\",\n                    null,\n                    10,\n                    new ResultValidator() {\n                        @Override\n                        public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n                            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n                            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n                            assertTrue(stdout.contains(\"starting testThread\"));\n                        }\n                    });\n        } else {\n            testStartup(\n                    \"resources.ThreadSpawner\",\n                    \"traces/ThreadStart.class\",\n                    null,\n                    20,\n                    new ResultValidator() {\n                        @Override\n                        public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n                            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n                            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n                            assertTrue(stdout.contains(\"starting testThread\"));\n                        }\n                    });\n        }\n    }\n\n  @Test\n  @DisplayName(\"Test HDR Histogram Metrics Integration\")\n  public void testMetrics() throws Exception {\n      testDynamic(\n        \"resources.Main\",\n        \"btrace/MetricsTest.java\",\n        20,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr\");\n            assertTrue(stdout.contains(\"=== HDR Histogram Metrics Test ===\"), \"Should contain metrics test header\");\n            assertTrue(stdout.contains(\"=== Metrics Report ===\"), \"Should contain metrics report\");\n            assertTrue(stdout.contains(\"Count:\"), \"Should contain count\");\n            assertTrue(stdout.contains(\"Mean:\"), \"Should contain mean\");\n            assertTrue(stdout.contains(\"P50:\"), \"Should contain P50\");\n            assertTrue(stdout.contains(\"P95:\"), \"Should contain P95\");\n            assertTrue(stdout.contains(\"P99:\"), \"Should contain P99\");\n          }\n        });\n  }\n\n  private static boolean isVersionSafeForJfr(String rtVersion) {\n      System.out.println(\"===> version: \" + rtVersion);\n    String[] versionParts = rtVersion.split(\"\\\\+\")[0].split(\"\\\\.\");\n    int major = Integer.parseInt(versionParts[0]);\n    String updateStr = versionParts.length == 3 ? versionParts[2].replace(\"0_\", \"\") : \"0\";\n    int idx = updateStr.indexOf('-');\n    if (idx > -1) {\n        updateStr = updateStr.substring(0, idx);\n    }\n    int update = Integer.parseInt(updateStr);\n    if (major == 8) {\n      // before 8u272 there was no JFR support\n      return update > 272;\n    } else if (major > 9) { // in JDK 9 the dynamic JFR events are missing\n      if (major == 11) {\n        // 11.0.9 and 11.0.10 are containing a bug causing the JFR initialization from BTrace to go\n        // into infinite loop\n        return update < 9 || update > 11;\n      }\n      return true;\n    }\n    return false;\n  }\n\n    private static boolean isVersionSafeForTraceAll(String rtVersion) {\n        System.out.println(\"===> version: \" + rtVersion);\n        String[] versionParts = rtVersion.split(\"\\\\+\")[0].split(\"\\\\.\");\n        int major = Integer.parseInt(versionParts[0]);\n        String updateStr = versionParts.length == 3 ? versionParts[2].replace(\"0_\", \"\") : \"0\";\n        int idx = updateStr.indexOf('-');\n        if (idx > -1) {\n            updateStr = updateStr.substring(0, idx);\n        }\n        int update = Integer.parseInt(updateStr);\n        // currently, an attempt to instrument all classes and methods will result in crash in jplis agent for JDK 17\n        if (major == 17) {\n            return false;\n        }\n        return true;\n    }\n\n  @Test\n  public void testOnelinerMethodEntry() throws Exception {\n    testDynamicOneliner(\n        \"resources.Main\",\n        \"resources.Main::callA @entry { print method }\",\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr: \" + stderr);\n            assertTrue(stdout.contains(\"callA\"), \"Method entry not captured\");\n          }\n        });\n  }\n\n  @Test\n  public void testOnelinerWithArguments() throws Exception {\n    testDynamicOneliner(\n        \"resources.Main\",\n        \"resources.Main::callB @entry { print args }\",\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr: \" + stderr);\n            assertTrue(stdout.contains(\"[1, Hello World]\"), \"Arguments not captured correctly\");\n          }\n        });\n  }\n\n  @Test\n  public void testOnelinerWithReturn() throws Exception {\n    testDynamicOneliner(\n        \"resources.Main\",\n        \"resources.Main::callB @return { print method, duration }\",\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr: \" + stderr);\n            assertTrue(stdout.contains(\"callB\"), \"Return method name not captured\");\n          }\n        });\n  }\n\n  @Test\n  public void testOnelinerWithRegexClassMatch() throws Exception {\n    testDynamicOneliner(\n        \"resources.Main\",\n        \"/resources\\\\..*Main/::callA @entry { print method }\",\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr: \" + stderr);\n            assertTrue(stdout.contains(\"callA\"), \"Regex class matching not working\");\n          }\n        });\n  }\n\n  @Test\n  public void testOnelinerStack() throws Exception {\n    testDynamicOneliner(\n        \"resources.Main\",\n        \"resources.Main::callB @entry { stack }\",\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n            assertTrue(stderr.isEmpty(), \"Non-empty stderr: \" + stderr);\n            assertTrue(\n                stdout.contains(\"resources.Main.callA\") || stdout.contains(\"resources.Main\"),\n                \"Stack trace not captured\");\n          }\n        });\n  }\n\n  @Test\n  public void testOnelinerCompilationError() throws Exception {\n    testDynamicOneliner(\n        \"resources.Main\",\n        \"resources.Main::callB @invalid { print }\",\n        5,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            // Compilation errors should be reported\n            assertTrue(\n                !stderr.isEmpty() || stdout.contains(\"error\") || stdout.contains(\"Error\"),\n                \"Expected compilation error not reported\");\n          }\n        });\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/java/tests/ExtensionLifecycleIntegrationTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage tests;\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * Integration tests for Extension lifecycle management.\n *\n * <p>Validates that Extension.initialize() and close() are called correctly during script\n * execution and detachment.\n */\npublic class ExtensionLifecycleIntegrationTest extends RuntimeTest {\n\n  @BeforeAll\n  public static void setup() throws Exception {\n    classSetup();\n  }\n\n  @BeforeEach\n  @Override\n  public void reset() {\n    super.reset();\n    // Use an ephemeral port to avoid conflicts with leaked agents from other test classes\n    try (ServerSocket ss = new ServerSocket(0)) {\n      btracePort = ss.getLocalPort();\n    } catch (IOException e) {\n      throw new RuntimeException(\"Failed to find a free port\", e);\n    }\n  }\n\n  @Test\n  public void testExtensionMethodCalled() throws Exception {\n    attachDelayMs = 500;\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/ExtensionLifecycleFullTest.java\",\n        new String[] {\"extensionCloseTest=true\"},\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n\n            // Validate extension method was called\n            assertTrue(\n                stdout.contains(\"LIFECYCLE: extension method called\"),\n                \"Extension method not called. stdout: \" + stdout);\n          }\n        });\n  }\n\n  @Test\n  public void testExtensionCloseCalledOnError() throws Exception {\n    attachDelayMs = 500;\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/ExtensionLifecycleErrorTest.java\",\n        new String[] {\"extensionCloseTest=true\"},\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertEquals(1, retcode, \"Script should have exited with code 1\");\n            // Extension should still be called even on error exit\n            assertTrue(\n                stdout.contains(\"LIFECYCLE: extension method called\"),\n                \"Extension method not called. stdout: \" + stdout);\n            assertTrue(\n                stdout.contains(\"Triggering error exit\"),\n                \"Error exit message not found. stdout: \" + stdout);\n          }\n        });\n  }\n\n  @Test\n  public void testMultipleExtensionsAllClosed() throws Exception {\n    attachDelayMs = 500;\n    testDynamic(\n        \"resources.Main\",\n        \"btrace/ExtensionLifecycleMultipleTest.java\",\n        new String[] {\"extensionCloseTest=true\"},\n        10,\n        new ResultValidator() {\n          @Override\n          public void validate(String stdout, String stderr, int retcode, String jfrFile) {\n            assertFalse(stdout.contains(\"FAILED\"), \"Script should not have failed\");\n\n            // Validate both extensions were called\n            assertTrue(\n                stdout.contains(\"LIFECYCLE: printer extension called\"),\n                \"Printer extension method not called. stdout: \" + stdout);\n            assertTrue(\n                stdout.contains(\"LIFECYCLE: metrics extension called\"),\n                \"Metrics extension method not called. stdout: \" + stdout);\n          }\n        });\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/java/tests/JBangAttachDockerTest.java",
    "content": "/*\n * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n */\n\npackage tests;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assumptions.assumeTrue;\n\nimport java.io.File;\nimport org.junit.jupiter.api.Assumptions;\nimport org.junit.jupiter.api.Tag;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.DockerClientFactory;\nimport org.testcontainers.containers.BindMode;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.utility.DockerImageName;\n\n@Tag(\"docker\")\npublic class JBangAttachDockerTest {\n  @Test\n  public void testAttachWithMaskedJar() throws Exception {\n    assumeTrue(Boolean.getBoolean(\"btrace.docker.available\"), \"Docker not available\");\n    boolean dockerReady = false;\n    try {\n      dockerReady = DockerClientFactory.instance().isDockerAvailable();\n    } catch (Exception e) {\n      dockerReady = false;\n    }\n    if (!dockerReady) {\n      System.err.println(\"[integration-tests] Docker not reachable by Testcontainers; skipping.\");\n    }\n    Assumptions.assumeTrue(dockerReady, \"Docker not reachable by Testcontainers\");\n\n    String libsDirPath = System.getProperty(\"btrace.libs\");\n    assertTrue(libsDirPath != null && !libsDirPath.isEmpty(), \"btrace.libs must be set\");\n    File libsDir = new File(libsDirPath);\n    assertTrue(libsDir.isDirectory(), \"btrace.libs must be a directory\");\n\n    File btraceJar = new File(libsDir, \"btrace.jar\");\n    assertTrue(btraceJar.isFile(), \"btrace.jar missing in libs directory\");\n\n    try (GenericContainer<?> container =\n        new GenericContainer<>(DockerImageName.parse(\"eclipse-temurin:21-jdk\"))\n            .withFileSystemBind(libsDir.getAbsolutePath(), \"/btrace/libs\", BindMode.READ_ONLY)\n            .withCommand(\"sleep\", \"300\")) {\n      container.start();\n\n      String targetSource =\n          \"public class Target {\\n\"\n              + \"  public static void main(String[] args) throws Exception {\\n\"\n              + \"    Thread.sleep(1500);\\n\"\n              + \"    for (int i = 0; i < 20; i++) {\\n\"\n              + \"      work();\\n\"\n              + \"      Thread.sleep(200);\\n\"\n              + \"    }\\n\"\n              + \"    Thread.sleep(2000);\\n\"\n              + \"  }\\n\"\n              + \"  static void work() {}\\n\"\n              + \"}\\n\";\n      Container.ExecResult result =\n          container.execInContainer(\n              \"bash\",\n              \"-lc\",\n              \"set -euo pipefail\\n\"\n                  + \"cat > /tmp/Target.java <<'EOF'\\n\"\n                  + targetSource\n                  + \"EOF\\n\"\n                  + \"cat > /tmp/TestTrace.java <<'EOF'\\n\"\n                  + \"import static org.openjdk.btrace.core.BTraceUtils.*;\\n\"\n                  + \"import org.openjdk.btrace.core.annotations.*;\\n\"\n                  + \"\\n\"\n                  + \"@BTrace\\n\"\n                  + \"public class TestTrace {\\n\"\n                  + \"  @OnMethod(clazz = \\\"Target\\\", method = \\\"work\\\")\\n\"\n                  + \"  public static void onWork() {\\n\"\n                  + \"    println(\\\"work\\\");\\n\"\n                  + \"  }\\n\"\n                  + \"}\\n\"\n                  + \"EOF\\n\"\n                  + \"javac /tmp/Target.java\\n\"\n                  + \"java -XX:+EnableDynamicAgentLoading -cp /tmp Target > /tmp/target.log 2>&1 &\\n\"\n                  + \"pid=$!\\n\"\n                  + \"sleep 1\\n\"\n                  + \"java -XX:+IgnoreUnrecognizedVMOptions \"\n                  + \"--add-opens java.base/jdk.internal.reflect=ALL-UNNAMED \"\n                  + \"--add-exports java.base/jdk.internal.reflect=ALL-UNNAMED \"\n                  + \"--add-modules jdk.attach \"\n                  + \"--add-exports jdk.attach/sun.tools.attach=ALL-UNNAMED \"\n                  + \"-jar /btrace/libs/btrace.jar ${pid} /tmp/TestTrace.java -v\\n\"\n                  + \"kill ${pid} >/dev/null 2>&1 || true\\n\");\n\n      String output = result.getStdout() + result.getStderr();\n      assertEquals(0, result.getExitCode(), \"btrace attach command failed\\nOutput:\\n\" + output);\n      assertTrue(output.contains(\"work\"), \"expected probe output missing\");\n    }\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/java/tests/RuntimeTest.java",
    "content": "/*\n * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.\n * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n *\n * This code is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License version 2 only, as\n * published by the Free Software Foundation.  Oracle designates this\n * particular file as subject to the \"Classpath\" exception as provided\n * by Oracle in the LICENSE file that accompanied this code.\n *\n * This code is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * version 2 for more details (a copy is included in the LICENSE file that\n * accompanied this code).\n *\n * You should have received a copy of the GNU General Public License version\n * 2 along with this work; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n *\n * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n * or visit www.oracle.com if you need additional information or have any\n * questions.\n */\npackage tests;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.openjdk.btrace.client.Client;\nimport org.openjdk.btrace.core.comm.BinaryWireProtocol;\nimport org.openjdk.btrace.core.comm.Command;\nimport org.openjdk.btrace.core.comm.JavaSerializationProtocol;\nimport org.openjdk.btrace.core.comm.ListProbesCommand;\nimport org.openjdk.btrace.core.comm.ProtocolConfig;\nimport org.openjdk.btrace.core.comm.ProtocolNegotiator;\nimport org.openjdk.btrace.core.comm.ProtocolVersion;\nimport org.openjdk.btrace.core.comm.WireProtocol;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.PrintWriter;\nimport java.net.Socket;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.FileVisitResult;\nimport java.nio.file.FileVisitor;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * @author Jaroslav Bachorik\n */\n@SuppressWarnings(\"ConstantConditions\")\npublic abstract class RuntimeTest {\n  private static String cp = null;\n  private static String targetAppCp = null;\n  protected static String javaHome = null;\n  private static String clientClassPath = null;\n  private static String eventsClassPath = null;\n  private static Path projectRoot = null;\n  private static boolean forceDebug = false;\n  private static String permissionsFile = null;\n  private static long defaultTimeoutMs = 10000L;\n  /** Try starting JFR recording if available */\n  private boolean startJfr = false;\n  /** Display the otput from the test application */\n  protected boolean debugTestApp = false;\n  /** Run BTrace in debug mode */\n  protected boolean debugBTrace = false;\n  /** Run BTrace in unsafe mode */\n  protected boolean isUnsafe = false;\n  /** Timeout in ms to wait for the expected BTrace output */\n  protected long timeout = 10000L;\n  /** Track retransforming progress */\n  protected boolean trackRetransforms = false;\n  /** Disconnect after status OK (client -x) */\n  protected boolean unattended = false;\n  /** Delay before client attach (ms) */\n  protected long attachDelayMs = 0;\n  /** Dump generated oneliner source */\n  protected boolean dumpOneliner = false;\n  /** Dump verifier errors in target JVM */\n  protected boolean dumpVerifierErrors = false;\n  /** Override the BTrace agent/client port (0 = use default 2020) */\n  protected int btracePort = 0;\n  /** Provide extra JVM args */\n  private static final List<String> extraJvmArgs = new ArrayList<>();\n\n  protected boolean attachDebugger = false;\n\n  public static void classSetup() {\n    if (System.getProperty(\"btrace.comm.protocol\") == null) {\n      System.setProperty(\"btrace.comm.protocol\", \"2\");\n    }\n    if (System.getProperty(\"btrace.comm.autoNegotiate\") == null) {\n      System.setProperty(\"btrace.comm.autoNegotiate\", \"false\");\n    }\n    if (System.getProperty(\"btrace.comm.forceVersion\") == null) {\n      System.setProperty(\"btrace.comm.forceVersion\", \"true\");\n    }\n    String forceDebugVal = System.getProperty(\"btrace.test.debug\");\n    if (forceDebugVal == null) {\n      forceDebugVal = System.getenv(\"BTRACE_TEST_DEBUG\");\n    }\n    forceDebug = Boolean.parseBoolean(forceDebugVal);\n    Path libsPath = Paths.get(System.getProperty(\"btrace.libs\"));\n    projectRoot = Paths.get(System.getProperty(\"project.dir\"));\n    Path btraceJarPath = libsPath.resolve(\"btrace.jar\");\n\n    Assertions.assertTrue(\n        Files.isRegularFile(btraceJarPath),\n        \"btrace.jar missing in libs directory\");\n    Path eventsJarPath = projectRoot.resolve(\"build/libs/events.jar\");\n    clientClassPath = btraceJarPath.toString();\n    eventsClassPath = eventsJarPath.toString();\n\n    cp =\n        btraceJarPath\n            + File.pathSeparator\n            + projectRoot.resolve(\"build/classes/java/test\")\n            + File.pathSeparator\n            + projectRoot.resolve(\"build/resources/test\")\n            + File.pathSeparator\n            + eventsClassPath;\n\n    // Target app classpath without btrace.jar - btrace is attached as agent\n    targetAppCp =\n        projectRoot.resolve(\"build/classes/java/test\")\n            + File.pathSeparator\n            + projectRoot.resolve(\"build/resources/test\")\n            + File.pathSeparator\n            + eventsClassPath;\n\n    Assertions.assertNotNull(projectRoot);\n    Assertions.assertNotNull(clientClassPath);\n\n    String toolsjar = null;\n    // Accept both TEST_JAVA_HOME (preferred) and JAVA_TEST_HOME as aliases\n    // TEST_JAVA_HOME has the highest precedence\n    javaHome = System.getenv(\"TEST_JAVA_HOME\");\n    if (javaHome == null) {\n      javaHome = System.getenv(\"JAVA_TEST_HOME\");\n    }\n    if (javaHome == null) {\n      javaHome = System.getenv(\"JAVA_HOME\");\n    }\n    if (javaHome == null) {\n      javaHome = System.getProperty(\"java.home\");\n    }\n    if (javaHome == null) {\n      throw new IllegalStateException(\"Missing TEST_JAVA_HOME or JAVA_HOME env variables\");\n    }\n    javaHome = javaHome.replace(\"/jre\", \"\");\n\n    Path toolsJarPath = Paths.get(javaHome, \"lib\", \"tools.jar\");\n    if (Files.exists(toolsJarPath)) {\n      toolsjar = toolsJarPath.toString();\n    }\n    cp = toolsjar != null ? cp + File.pathSeparator + toolsjar : cp;\n    System.out.println(\"=== Using Java: \" + javaHome + \", cp: \" + cp);\n\n    // Forward any btrace.* system properties to the traced app via JVM args\n    // so the agent/client can pick them up (e.g., btrace.verify.transformed, debug flags).\n    try {\n      System.getProperties()\n          .stringPropertyNames()\n          .stream()\n          .filter(n -> n.startsWith(\"btrace.\"))\n          .forEach(n -> extraJvmArgs.add(\"-D\" + n + \"=\" + System.getProperty(n)));\n    } catch (Throwable ignore) {\n      // best effort; if this fails, tests still run with defaults\n    }\n\n    // Tune default timeout for newer JDKs which may exhibit slower attach/instrument timing\n    try {\n      Properties release = new Properties();\n      release.load(Files.newInputStream(Paths.get(javaHome, \"release\")));\n      String ver = release.getProperty(\"JAVA_VERSION\", \"\\\"0\\\"\").replace(\"\\\"\", \"\");\n      if (isVersionAtLeast(ver, 25)) {\n        defaultTimeoutMs = 20000L;\n      }\n    } catch (Exception ignore) {\n      // keep default\n    }\n\n    // Prepare permissions policy to allow privileged extensions for tests\n    try {\n      Path permsDir = projectRoot.resolve(\"build\");\n      Files.createDirectories(permsDir);\n      Path perms = permsDir.resolve(\"permissions.properties\");\n      String content = \"allowPrivileged=true\\n\" +\n                       \"allowExtensions=btrace-metrics,btrace-utils,btrace-statsd\\n\";\n      Files.write(perms, content.getBytes(StandardCharsets.UTF_8));\n      permissionsFile = perms.toAbsolutePath().toString();\n    } catch (IOException ioe) {\n      // best effort; leave permissionsFile null if we can't create it\n      permissionsFile = null;\n    }\n  }\n\n  protected void reset() {\n    debugTestApp = false;\n    debugBTrace = false;\n    isUnsafe = false;\n    unattended = false;\n    attachDelayMs = 0;\n    dumpOneliner = false;\n    dumpVerifierErrors = false;\n    btracePort = 0;\n    timeout = defaultTimeoutMs;\n  }\n\n  private static boolean isVersionAtLeast(String version, int majorThreshold) {\n    try {\n      // Accept forms like \"25\", \"25.0.1\", or legacy \"1.8.0_262\"\n      String v = version;\n      if (v.startsWith(\"1.\")) {\n        v = v.substring(2); // e.g., 8.0_262 -> 8.0_262\n      }\n      int dot = v.indexOf('.') == -1 ? v.length() : v.indexOf('.');\n      String majorStr = v.substring(0, dot);\n      int major = Integer.parseInt(majorStr.replaceAll(\"[^0-9]\", \"\"));\n      return major >= majorThreshold;\n    } catch (Throwable t) {\n      return false;\n    }\n  }\n\n  public void testWithJfr(String testApp, String testScript, int checkLines, ResultValidator v)\n      throws Exception {\n    startJfr = true;\n    test(testApp, testScript, checkLines, v);\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  public void testWithJfr(\n      String testApp, String testScript, String[] cmdArgs, int checkLines, ResultValidator v)\n      throws Exception {\n    startJfr = true;\n    testDynamic(testApp, testScript, cmdArgs, checkLines, v);\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  public void test(String testApp, String testScript, int checkLines, ResultValidator v)\n      throws Exception {\n    test(testApp, testScript, null, checkLines, v);\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  public void test(\n      String testApp, String testScript, String[] cmdArgs, int checkLines, ResultValidator v)\n      throws Exception {\n    testDynamic(testApp, testScript, cmdArgs, checkLines, v);\n    testStartup(testApp, testScript.replace(\".java\", \".class\"), cmdArgs, checkLines, v);\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  public void testDynamic(String testApp, String testScript, int checkLines, ResultValidator v)\n      throws Exception {\n    testDynamic(testApp, testScript, null, checkLines, v);\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  public void testDynamicOneliner(\n      String testApp, String oneliner, int checkLines, ResultValidator v) throws Exception {\n    testDynamicOneliner(testApp, oneliner, null, checkLines, v);\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  public void testDynamicOneliner(\n      String testApp, String oneliner, String[] cmdArgs, int checkLines, ResultValidator v)\n      throws Exception {\n    System.out.println(\"=== Dynamic attach (oneliner)\");\n    if (forceDebug) {\n      // force debug flags\n      debugBTrace = true;\n      debugTestApp = true;\n    }\n    String testJavaHome = System.getenv(\"TEST_JAVA_HOME\");\n    if (testJavaHome == null) {\n      testJavaHome = System.getenv(\"JAVA_TEST_HOME\");\n    }\n    testJavaHome = testJavaHome != null ? testJavaHome : System.getenv(\"JAVA_HOME\");\n    if (testJavaHome == null) {\n      throw new IllegalStateException(\"Missing TEST_JAVA_HOME or JAVA_HOME env variables\");\n    }\n    System.out.println(\"===> test java: \" + testJavaHome);\n    String jfrFile = null;\n    List<String> args = new ArrayList<>(Arrays.asList(testJavaHome + \"/bin/java\", \"-cp\", cp));\n    if (permissionsFile != null) {\n      args.add(\"-Dbtrace.permissions=\" + permissionsFile);\n    }\n    if (attachDebugger) {\n      args.add(\"-agentlib:jdwp=transport=dt_socket,server=y,address=8000\");\n    }\n    args.add(\"-XX:+AllowRedefinitionToAddDeleteMethods\");\n    args.add(\"-XX:+IgnoreUnrecognizedVMOptions\");\n    args.add(\"-XX:+EnableDynamicAgentLoading\");\n    args.add(\"-XX:+UnlockDiagnosticVMOptions\");\n    args.add(\"-XX:-OmitStackTraceInFastThrow\");\n    if (dumpVerifierErrors) {\n      args.add(\"-Dbtrace.verifier.dump=true\");\n    }\n    args.addAll(extraJvmArgs);\n    if (startJfr) {\n      jfrFile = Files.createTempFile(\"btrace-\", \".jfr\").toString();\n      args.add(\"-XX:StartFlightRecording=settings=default,dumponexit=true,filename=\" + jfrFile);\n    }\n    args.add(\"-Dbtrace.test=test\");\n    args.add(testApp);\n\n    ProcessBuilder pb = new ProcessBuilder(args);\n    pb.environment().remove(\"JAVA_TOOL_OPTIONS\");\n\n    Process p = pb.start();\n    PrintWriter pw = new PrintWriter(p.getOutputStream());\n\n    StringBuilder stdout = new StringBuilder();\n    StringBuilder stderr = new StringBuilder();\n    AtomicInteger ret = new AtomicInteger(-1);\n\n    BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(p.getInputStream()));\n\n    CountDownLatch testAppLatch = new CountDownLatch(1);\n    AtomicReference<String> pidStringRef = new AtomicReference<>();\n\n    Thread outT =\n        new Thread(\n            () -> {\n              try {\n                String l;\n                while ((l = stdoutReader.readLine()) != null) {\n                  if (l.startsWith(\"ready:\")) {\n                    pidStringRef.set(l.split(\":\")[1]);\n                    testAppLatch.countDown();\n                  }\n                  if (debugTestApp) {\n                    System.out.println(\"[traced app] \" + l);\n                  }\n                }\n\n              } catch (Exception e) {\n                e.printStackTrace(System.err);\n              }\n            },\n            \"STDOUT Reader\");\n    outT.setDaemon(true);\n\n    BufferedReader stderrReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));\n\n    Thread errT =\n        new Thread(\n            () -> {\n              try {\n                String l = null;\n                while ((l = stderrReader.readLine()) != null) {\n                  if (l.contains(\"Server VM warning\")\n                      || l.contains(\"XML libraries not available\")\n                      || l.contains(\"terminally deprecated method in sun.misc.Unsafe\")\n                      || l.contains(\"sun.misc.Unsafe::objectFieldOffset\")\n                      || l.contains(\"org.jctools.util.UnsafeAccess\")\n                      || l.contains(\"ASM verification requested for \")\n                      || l.contains(\"ASM verification OK for \")) {\n                    continue;\n                  }\n                  testAppLatch.countDown();\n                  if (debugTestApp) {\n                    System.err.println(\"[traced app] \" + l);\n                  }\n                }\n              } catch (Exception e) {\n                e.printStackTrace(System.err);\n              }\n            },\n            \"STDERR Reader\");\n    errT.setDaemon(true);\n\n    outT.start();\n    errT.start();\n\n    testAppLatch.await();\n    String pid = pidStringRef.get();\n    if (pid != null) {\n      System.out.println(\"Target process ready: \" + pid);\n      if (attachDelayMs > 0) {\n        try {\n          Thread.sleep(attachDelayMs);\n        } catch (InterruptedException ie) {\n          Thread.currentThread().interrupt();\n        }\n      }\n\n      Process client = attachOneliner(pid, oneliner, cmdArgs, checkLines, stdout, stderr);\n\n      System.out.println(\"Detached.\");\n\n      // Signal the target app to shut down\n      pw.println(\"done\");\n      pw.flush();\n\n      // Wait for the target process to exit gracefully\n      if (!p.waitFor(10, TimeUnit.SECONDS)) {\n        System.out.println(\"Target process did not exit in time, destroying.\");\n        p.destroyForcibly();\n      }\n\n      // Now wait for the client process (should exit quickly once target is gone)\n      if (!client.waitFor(10, TimeUnit.SECONDS)) {\n        System.out.println(\"Client process did not exit in time, destroying.\");\n        client.destroyForcibly();\n      }\n\n      ret.set(client.isAlive() ? -1 : client.exitValue());\n\n      outT.join(5000);\n      errT.join(5000);\n    }\n\n    // Allow a brief grace period for any final output to flush before validation\n    try {\n      Thread.sleep(500L);\n    } catch (InterruptedException ie) {\n      Thread.currentThread().interrupt();\n    }\n    // If JFR was enabled for dynamic attach, give it a moment and dump the recording\n    if (startJfr && pidStringRef.get() != null) {\n      try {\n        Thread.sleep(1500L);\n      } catch (InterruptedException ie) {\n        Thread.currentThread().interrupt();\n      }\n      try {\n        ProcessBuilder jcmdPb;\n        String jcmdExe =\n            testJavaHome != null ? Paths.get(testJavaHome, \"bin\", \"jcmd\").toString() : \"jcmd\";\n        if (jfrFile != null) {\n          jcmdPb =\n              new ProcessBuilder(\n                  jcmdExe, pidStringRef.get(), \"JFR.dump\", \"name=1\", \"filename=\" + jfrFile);\n        } else {\n          jcmdPb = new ProcessBuilder(jcmdExe, pidStringRef.get(), \"JFR.dump\", \"name=1\");\n        }\n        jcmdPb.start().waitFor();\n      } catch (Exception e) {\n        e.printStackTrace(System.err);\n      }\n    }\n\n    v.validate(stdout.toString(), stderr.toString(), ret.get(), jfrFile);\n  }\n\n  @SuppressWarnings(\"DefaultCharset\")\n  public void testDynamic(\n      String testApp, String testScript, String[] cmdArgs, int checkLines, ResultValidator v)\n      throws Exception {\n    System.out.println(\"=== Dynamic attach\");\n    if (forceDebug) {\n      // force debug flags\n      debugBTrace = true;\n      debugTestApp = true;\n    }\n    String testJavaHome = System.getenv(\"TEST_JAVA_HOME\");\n    if (testJavaHome == null) {\n      testJavaHome = System.getenv(\"JAVA_TEST_HOME\");\n    }\n    testJavaHome = testJavaHome != null ? testJavaHome : System.getenv(\"JAVA_HOME\");\n    if (testJavaHome == null) {\n      throw new IllegalStateException(\"Missing TEST_JAVA_HOME or JAVA_HOME env variables\");\n    }\n    System.out.println(\"===> test java: \" + testJavaHome);\n    String jfrFile = null;\n    List<String> args = new ArrayList<>(Arrays.asList(testJavaHome + \"/bin/java\", \"-cp\", targetAppCp));\n    if (permissionsFile != null) {\n      args.add(\"-Dbtrace.permissions=\" + permissionsFile);\n    }\n    if (attachDebugger) {\n      args.add(\"-agentlib:jdwp=transport=dt_socket,server=y,address=8000\");\n    }\n    args.add(\"-XX:+AllowRedefinitionToAddDeleteMethods\");\n    args.add(\"-XX:+IgnoreUnrecognizedVMOptions\");\n    args.add(\"-XX:+EnableDynamicAgentLoading\");\n    args.add(\"-XX:+UnlockDiagnosticVMOptions\");\n    args.add(\"-XX:-OmitStackTraceInFastThrow\");\n//    args.add(\"-Xlog\");\n\n    // uncomment the following line to get extra JFR logs\n    //    args.add(\"-Xlog:jfr*=trace\");\n    args.addAll(extraJvmArgs);\n    if (startJfr) {\n      jfrFile = Files.createTempFile(\"btrace-\", \".jfr\").toString();\n      args.add(\"-XX:StartFlightRecording=settings=default,dumponexit=true,filename=\" + jfrFile);\n    }\n    args.add(\"-Dbtrace.test=test\");\n    args.add(testApp);\n\n    ProcessBuilder pb = new ProcessBuilder(args);\n    pb.environment().remove(\"JAVA_TOOL_OPTIONS\");\n\n    Process p = pb.start();\n    PrintWriter pw = new PrintWriter(p.getOutputStream());\n\n    StringBuilder stdout = new StringBuilder();\n    StringBuilder stderr = new StringBuilder();\n    AtomicInteger ret = new AtomicInteger(-1);\n\n    BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(p.getInputStream()));\n\n    CountDownLatch testAppLatch = new CountDownLatch(1);\n    AtomicReference<String> pidStringRef = new AtomicReference<>();\n\n    Thread outT =\n        new Thread(\n            () -> {\n              try {\n                String l;\n                while ((l = stdoutReader.readLine()) != null) {\n                  if (l.startsWith(\"ready:\")) {\n                    pidStringRef.set(l.split(\":\")[1]);\n                    testAppLatch.countDown();\n                  }\n                  if (debugTestApp) {\n                    System.out.println(\"[traced app] \" + l);\n                  }\n                }\n\n              } catch (Exception e) {\n                e.printStackTrace(System.err);\n              }\n            },\n            \"STDOUT Reader\");\n    outT.setDaemon(true);\n\n    BufferedReader stderrReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));\n\n    Thread errT =\n        new Thread(\n            () -> {\n              try {\n                String l = null;\n                while ((l = stderrReader.readLine()) != null) {\n                  if (l.contains(\"Server VM warning\")\n                      || l.contains(\"XML libraries not available\")\n                      || l.contains(\"terminally deprecated method in sun.misc.Unsafe\")\n                      || l.contains(\"sun.misc.Unsafe::objectFieldOffset\")\n                      || l.contains(\"org.jctools.util.UnsafeAccess\")\n                      || l.contains(\"ASM verification requested for \")\n                      || l.contains(\"ASM verification OK for \")) {\n                    continue;\n                  }\n                  testAppLatch.countDown();\n                  if (debugTestApp) {\n                    System.err.println(\"[traced app] \" + l);\n                  }\n                }\n              } catch (Exception e) {\n                e.printStackTrace(System.err);\n              }\n            },\n            \"STDERR Reader\");\n    errT.setDaemon(true);\n\n    outT.start();\n    errT.start();\n\n    testAppLatch.await();\n    String pid = pidStringRef.get();\n    if (pid != null) {\n      System.out.println(\"Target process ready: \" + pid);\n      if (attachDelayMs > 0) {\n        try {\n          Thread.sleep(attachDelayMs);\n        } catch (InterruptedException ie) {\n          Thread.currentThread().interrupt();\n        }\n      }\n\n      Process client = attach(pid, testScript, cmdArgs, checkLines, stdout, stderr);\n\n      System.out.println(\"Detached.\");\n\n      // Signal the target app to shut down\n      pw.println(\"done\");\n      pw.flush();\n\n      // Wait for the target process to exit gracefully\n      if (!p.waitFor(10, TimeUnit.SECONDS)) {\n        System.out.println(\"Target process did not exit in time, destroying.\");\n        p.destroyForcibly();\n      }\n\n      // Now wait for the client process (should exit quickly once target is gone)\n      if (!client.waitFor(10, TimeUnit.SECONDS)) {\n        System.out.println(\"Client process did not exit in time, destroying.\");\n        client.destroyForcibly();\n      }\n\n      ret.set(client.isAlive() ? -1 : client.exitValue());\n\n      outT.join(5000);\n      errT.join(5000);\n    }\n\n    // Allow a brief grace period for any final output to flush before validation\n    try {\n      Thread.sleep(500L);\n    } catch (InterruptedException ie) {\n      Thread.currentThread().interrupt();\n    }\n    // If JFR was enabled for dynamic attach, give it a moment and dump the recording\n    if (startJfr && pidStringRef.get() != null) {\n      try {\n        Thread.sleep(1500L);\n      } catch (InterruptedException ie) {\n        Thread.currentThread().interrupt();\n      }\n      try {\n        ProcessBuilder jcmdPb;\n        String jcmdExe = testJavaHome != null ? Paths.get(testJavaHome, \"bin\", \"jcmd\").toString() : \"jcmd\";\n        if (jfrFile != null) {\n          jcmdPb =\n              new ProcessBuilder(\n                  jcmdExe, pidStringRef.get(), \"JFR.dump\", \"name=1\", \"filename=\" + jfrFile);\n        } else {\n          jcmdPb = new ProcessBuilder(jcmdExe, pidStringRef.get(), \"JFR.dump\", \"name=1\");\n        }\n        jcmdPb.start().waitFor();\n      } catch (Exception ignore) {\n        // best effort\n      }\n    }\n\n    v.validate(stdout.toString(), stderr.toString(), ret.get(), jfrFile);\n  }\n\n  public void testStartup(\n      String testApp, String testScript, String[] cmdArgs, int checkLines, ResultValidator v)\n      throws Exception {\n    System.out.println(\"=== On-Startup\");\n    Path agentPath = locateAgent();\n    if (agentPath == null) {\n      throw new RuntimeException(\"Missing btrace.jar or btrace-agent.jar\");\n    }\n    if (forceDebug) {\n      // force debug flags\n      debugBTrace = true;\n      debugTestApp = true;\n    }\n    String testJavaHome = System.getenv(\"TEST_JAVA_HOME\");\n    if (testJavaHome == null) {\n      testJavaHome = System.getenv(\"JAVA_TEST_HOME\");\n    }\n    testJavaHome = testJavaHome != null ? testJavaHome : System.getenv(\"JAVA_HOME\");\n    if (testJavaHome == null) {\n      throw new IllegalStateException(\"Missing TEST_JAVA_HOME or JAVA_HOME env variables\");\n    }\n    String jfrFile = null;\n    List<String> args = new ArrayList<>(Arrays.asList(testJavaHome + \"/bin/java\", \"-cp\", targetAppCp));\n    if (permissionsFile != null) {\n      args.add(\"-Dbtrace.permissions=\" + permissionsFile);\n    }\n    if (attachDebugger) {\n      args.add(\"-agentlib:jdwp=transport=dt_socket,server=y,address=8000\");\n    }\n    args.add(\"-XX:+AllowRedefinitionToAddDeleteMethods\");\n    args.add(\"-XX:+IgnoreUnrecognizedVMOptions\");\n    args.add(\"-XX:+UnlockDiagnosticVMOptions\");\n//    args.add(\"-Xlog:exceptions\");\n    // uncomment the following line to get extra JFR logs\n    //    args.add(\"-Xlog:jfr*=trace\");\n    args.addAll(extraJvmArgs);\n    if (startJfr) {\n      jfrFile = Files.createTempFile(\"btrace-\", \".jfr\").toString();\n      args.add(\"-XX:StartFlightRecording=settings=default,dumponexit=true,filename=\" + jfrFile);\n    }\n\n    String agentSetup =\n        \"-javaagent:\"\n            + agentPath\n            + \"=script=\"\n            + locateTrace(testScript)\n            + \",scriptOutputFile=::stdout\";\n    if (debugBTrace) {\n      agentSetup += \",debug=true,dumpClasses=true,dumpDir=/tmp/btrace\";\n    }\n    args.add(agentSetup);\n    args.add(testApp);\n\n    ProcessBuilder pb = new ProcessBuilder(args);\n    pb.environment().remove(\"JAVA_TOOL_OPTIONS\");\n\n    Process p = pb.start();\n    PrintWriter pw = new PrintWriter(p.getOutputStream());\n\n    StringBuilder stdout = new StringBuilder();\n    StringBuilder stderr = new StringBuilder();\n    AtomicInteger ret = new AtomicInteger(-1);\n\n    BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(p.getInputStream()));\n\n    CountDownLatch testAppLatch = new CountDownLatch(1);\n    CountDownLatch stdoutLatch = new CountDownLatch(checkLines);\n    AtomicReference<String> pidStringRef = new AtomicReference<>();\n\n    Thread outT =\n        new Thread(\n            () -> {\n              try {\n                String l;\n                while ((l = stdoutReader.readLine()) != null) {\n                  stdout.append(l).append(System.lineSeparator());\n                  if (l.startsWith(\"ready:\")) {\n                    pidStringRef.set(l.split(\"\\\\:\")[1]);\n                    testAppLatch.countDown();\n                  } else {\n                    stdoutLatch.countDown();\n                  }\n                  if (debugTestApp) {\n                    System.out.println(\"[traced app] \" + l);\n                  }\n                }\n\n              } catch (Exception e) {\n                e.printStackTrace(System.err);\n              }\n            },\n            \"STDOUT Reader\");\n    outT.setDaemon(true);\n\n    BufferedReader stderrReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));\n\n    Thread errT =\n        new Thread(\n            () -> {\n              try {\n                String l = null;\n                while ((l = stderrReader.readLine()) != null) {\n                  if (l.contains(\"SLF4J\")\n                      || l.contains(\"Server VM warning\")\n                      || l.contains(\"XML\")\n                      || l.contains(\"Successfully started BTrace probe\")\n                      || l.contains(\"terminally deprecated method in sun.misc.Unsafe\")\n                      || l.contains(\"sun.misc.Unsafe::objectFieldOffset\")\n                      || l.contains(\"org.jctools.util.UnsafeAccess\")\n                      || l.contains(\"ASM verification requested for \")\n                      || l.contains(\"ASM verification OK for \")\n                      || l.contains(\"A restricted method\")\n                      || l.contains(\"has been called by\")\n                      || l.contains(\"enable-native-access\")\n                      || l.contains(\"Restricted methods will be blocked\")) {\n                    continue;\n                  }\n                  stderr.append(l).append(System.lineSeparator());\n                  if (l.contains(\"Server VM warning\")\n                      || l.contains(\"XML libraries not available\")) {\n                    continue;\n                  }\n                  if (debugTestApp) {\n                    System.err.println(\"[traced app] \" + l);\n                  }\n                  testAppLatch.countDown();\n                  for (int i = 0; i < checkLines; i++) {\n                    stdoutLatch.countDown();\n                  }\n                }\n              } catch (Exception e) {\n                e.printStackTrace(System.err);\n              }\n            },\n            \"STDERR Reader\");\n    errT.setDaemon(true);\n\n    outT.start();\n    errT.start();\n\n    testAppLatch.await();\n    stdoutLatch.await();\n    // Allow some time for late BTrace output to flush in on-startup mode.\n    try {\n      Thread.sleep(1000L);\n    } catch (InterruptedException ie) {\n      Thread.currentThread().interrupt();\n    }\n\n    if (startJfr && pidStringRef.get() != null) {\n      // Give the periodic event at least one interval to fire before dumping\n      try {\n        Thread.sleep(1500L);\n      } catch (InterruptedException ie) {\n        Thread.currentThread().interrupt();\n      }\n      // Dump the current recording into the configured file to ensure events are flushed\n      ProcessBuilder jcmdPb;\n      String jcmdExe = testJavaHome != null ? Paths.get(testJavaHome, \"bin\", \"jcmd\").toString() : \"jcmd\";\n      if (jfrFile != null) {\n        jcmdPb = new ProcessBuilder(jcmdExe, pidStringRef.get(), \"JFR.dump\", \"name=1\", \"filename=\" + jfrFile);\n      } else {\n        jcmdPb = new ProcessBuilder(jcmdExe, pidStringRef.get(), \"JFR.dump\", \"name=1\");\n      }\n      jcmdPb.start().waitFor();\n    }\n\n    v.validate(stdout.toString(), stderr.toString(), ret.get(), jfrFile);\n\n    // Clean up the target process\n    pw.println(\"done\");\n    pw.flush();\n    if (!p.waitFor(10, TimeUnit.SECONDS)) {\n      p.destroyForcibly();\n    }\n  }\n\n  protected Path locateAgent() {\n    Path start = projectRoot.resolve(\"../btrace-dist/build/resources/main\");\n    // [0] = masked btrace.jar, [1] = old btrace-agent.jar\n    Path[] tracePath = new Path[2];\n    try {\n      Files.walkFileTree(\n          start,\n          new FileVisitor<Path>() {\n            @Override\n            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)\n                throws IOException {\n              return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)\n                throws IOException {\n              String fileName = file.getFileName().toString();\n              if (fileName.equals(\"btrace.jar\")) {\n                // Prefer the new masked btrace.jar\n                tracePath[0] = file;\n                return FileVisitResult.TERMINATE;\n              }\n              if (fileName.equals(\"btrace-agent.jar\") && tracePath[1] == null) {\n                // Fall back to old btrace-agent.jar\n                tracePath[1] = file;\n              }\n              return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {\n              return FileVisitResult.TERMINATE;\n            }\n\n            @Override\n            public FileVisitResult postVisitDirectory(Path dir, IOException exc)\n                throws IOException {\n              return FileVisitResult.CONTINUE;\n            }\n          });\n    } catch (IOException e) {\n      e.printStackTrace();\n    }\n    // Prefer masked btrace.jar, fall back to btrace-agent.jar\n    return tracePath[0] != null ? tracePath[0] : tracePath[1];\n  }\n\n  public static final class TestApp {\n    private int pid;\n    private final CountDownLatch testAppLatch = new CountDownLatch(1);\n    private final Process process;\n\n    public TestApp(Process process, boolean debug) {\n      this.process = process;\n\n      BufferedReader stdoutReader =\n          new BufferedReader(new InputStreamReader(process.getInputStream()));\n\n      Thread outT =\n          new Thread(\n              () -> {\n                try {\n                  String l;\n                  while ((l = stdoutReader.readLine()) != null) {\n                    if (l.startsWith(\"ready:\")) {\n                      pid = Integer.parseInt(l.split(\":\")[1]);\n                      testAppLatch.countDown();\n                    }\n                    if (debug) {\n                      System.out.println(\"[traced app] \" + l);\n                    }\n                  }\n\n                } catch (Exception e) {\n                  e.printStackTrace(System.err);\n                }\n              },\n              \"STDOUT Reader\");\n      outT.setDaemon(true);\n\n      BufferedReader stderrReader =\n          new BufferedReader(new InputStreamReader(process.getErrorStream()));\n\n      Thread errT =\n          new Thread(\n              () -> {\n                try {\n                  String l = null;\n                  while ((l = stderrReader.readLine()) != null) {\n                    if (l.contains(\"Server VM warning\")\n                        || l.contains(\"XML libraries not available\")) {\n                      continue;\n                    }\n                    testAppLatch.countDown();\n                    if (debug) {\n                      System.err.println(\"[traced app] \" + l);\n                    }\n                  }\n                } catch (Exception e) {\n                  e.printStackTrace(System.err);\n                }\n              },\n              \"STDERR Reader\");\n      errT.setDaemon(true);\n\n      outT.start();\n      errT.start();\n    }\n\n    public void stop() throws InterruptedException {\n      if (process.isAlive()) {\n        PrintWriter pw = new PrintWriter(process.getOutputStream());\n        pw.println(\"done\");\n        pw.flush();\n        process.waitFor();\n      }\n    }\n\n    public int getPid() throws InterruptedException {\n      testAppLatch.await();\n      return pid;\n    }\n  }\n\n  public TestApp launchTestApp(String testApp, String... cmdArgs) throws Exception {\n    if (forceDebug) {\n      // force debug flags\n      debugBTrace = true;\n      debugTestApp = true;\n    }\n    String testJavaHome = System.getenv(\"TEST_JAVA_HOME\");\n    testJavaHome = testJavaHome != null ? testJavaHome : System.getenv(\"JAVA_HOME\");\n    if (testJavaHome == null) {\n      throw new IllegalStateException(\"Missing TEST_JAVA_HOME or JAVA_HOME env variables\");\n    }\n    String jfrFile = null;\n    List<String> args = new ArrayList<>(Arrays.asList(testJavaHome + \"/bin/java\", \"-cp\", cp));\n    if (attachDebugger) {\n      args.add(\"-agentlib:jdwp=transport=dt_socket,server=y,address=8000\");\n    }\n    args.add(\"-XX:+AllowRedefinitionToAddDeleteMethods\");\n    args.add(\"-XX:+IgnoreUnrecognizedVMOptions\");\n    // uncomment the following line to get extra JFR logs\n    //    args.add(\"-Xlog:jfr*=trace\");\n    args.addAll(extraJvmArgs);\n    if (startJfr) {\n      jfrFile = Files.createTempFile(\"btrace-\", \".jfr\").toString();\n      args.add(\"-XX:StartFlightRecording=settings=default,dumponexit=true,filename=\" + jfrFile);\n    }\n    args.add(testApp);\n\n    ProcessBuilder pb = new ProcessBuilder(args);\n    pb.environment().remove(\"JAVA_TOOL_OPTIONS\");\n\n    return new TestApp(pb.start(), debugTestApp);\n  }\n\n  public interface ProcessOutputProcessor {\n    boolean onStdout(int lineno, String line);\n\n    boolean onStderr(int lineno, String line);\n  }\n\n  public void runBTrace(String[] args, ProcessOutputProcessor outputProcessor) throws Exception {\n    List<String> argVals =\n        new ArrayList<>(\n            Arrays.asList(\n                javaHome + \"/bin/java\",\n                \"-cp\",\n                cp,\n                \"org.openjdk.btrace.boot.Loader\",\n                debugBTrace ? \"-v\" : \"\",\n                \"-cp\",\n                eventsClassPath,\n                \"-d\",\n                Paths.get(System.getProperty(\"java.io.tmpdir\"), \"btrace-test\").toString()));\n    argVals.addAll(Arrays.asList(args));\n    if (Files.exists(Paths.get(javaHome, \"jmods\"))) {\n      argVals.addAll(\n          1,\n          Arrays.asList(\n              \"--add-exports\",\n              \"jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\",\n              \"--add-modules\",\n              \"jdk.attach\",\n              \"--add-exports\",\n              \"jdk.attach/sun.tools.attach=ALL-UNNAMED\"));\n    }\n\n    ProcessBuilder pb = new ProcessBuilder(argVals);\n\n    pb.environment().remove(\"JAVA_TOOL_OPTIONS\");\n    Process p = pb.start();\n\n    AtomicBoolean done = new AtomicBoolean(false);\n\n    Thread stderrThread =\n        new Thread(\n            () -> {\n              try {\n                BufferedReader br =\n                    new BufferedReader(\n                        new InputStreamReader(p.getErrorStream(), StandardCharsets.UTF_8));\n\n                int lineno = 0;\n                String line = null;\n                boolean callbackActive = true;\n                while ((line = br.readLine()) != null) {\n                  System.out.println(\"[btrace err] \" + line);\n                  if (line.contains(\"Server VM warning\")\n                      || line.contains(\"XML libraries not available\")\n                      || line.contains(\"Successfully started BTrace probe\")\n                      || line.contains(\"Connection reset\")) {\n                    // skip JVM generated warnings\n                    continue;\n                  }\n                  if (line.startsWith(\"[traced app]\") || line.startsWith(\"[btrace out]\")) {\n                    // skip test debug lines\n                    continue;\n                  }\n                  if (callbackActive && !outputProcessor.onStderr(++lineno, line)) {\n                    callbackActive = false;\n                    // Continue draining output to prevent buffer fill-up and deadlock,\n                    // but stop calling the callback\n                    done.set(true);\n                  }\n                  ;\n                }\n              } catch (Exception e) {\n                throw new Error(e);\n              }\n            },\n            \"Stderr Reader\");\n\n    Thread stdoutThread =\n        new Thread(\n            () -> {\n              try {\n                BufferedReader br =\n                    new BufferedReader(\n                        new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8));\n                int lineno = 1;\n                String line = null;\n                boolean callbackActive = true;\n                while ((line = br.readLine()) != null) {\n                  if (callbackActive && !outputProcessor.onStdout(lineno, line)) {\n                    callbackActive = false;\n                    // Continue draining output to prevent buffer fill-up and deadlock,\n                    // but stop calling the callback\n                    done.set(true);\n                  }\n                  if (!(debugBTrace && line.contains(\"DEBUG\"))) {\n                    lineno++;\n                  }\n                }\n              } catch (Exception e) {\n                throw new Error(e);\n              }\n            },\n            \"Stdout Reader\");\n\n    stderrThread.setDaemon(true);\n    stdoutThread.setDaemon(true);\n\n    stderrThread.start();\n    stdoutThread.start();\n\n    // Wait adaptively: if callbacks indicate completion (done=true), shorten wait and terminate\n    long deadline = System.currentTimeMillis() + 30000; // 30s max\n    while ((stderrThread.isAlive() || stdoutThread.isAlive()) && System.currentTimeMillis() < deadline) {\n      if (done.get()) {\n        // Give the client a brief grace period to exit on its own\n        try { Thread.sleep(200); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); }\n        if (p.isAlive()) {\n          p.destroy();\n          try { Thread.sleep(200); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); }\n          if (p.isAlive()) {\n            p.destroyForcibly();\n          }\n        }\n        // After short-circuiting, only wait up to 1s more for threads to drain\n        deadline = System.currentTimeMillis() + 1000;\n      }\n      try { Thread.sleep(100); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); }\n    }\n\n    // If threads are still alive, process likely hung - destroy it\n    if (stderrThread.isAlive() || stdoutThread.isAlive()) {\n      System.err.println(\"WARNING: BTrace process output threads still alive after timeout, destroying process\");\n      p.destroyForcibly();\n      // Give threads a moment to notice process died\n      stderrThread.join(1000);\n      stdoutThread.join(1000);\n    }\n  }\n\n  public Process runBTrace(\n      String[] args, int checkLines, StringBuilder stdout, StringBuilder stderr) throws Exception {\n    List<String> argVals =\n        new ArrayList<>(\n            Arrays.asList(\n                javaHome + \"/bin/java\",\n                \"-cp\",\n                cp,\n                \"org.openjdk.btrace.boot.Loader\",\n                debugBTrace ? \"-v\" : \"\",\n                \"-cp\",\n                eventsClassPath,\n                \"-d\",\n                Paths.get(System.getProperty(\"java.io.tmpdir\"), \"btrace-test\").toString()));\n    argVals.addAll(Arrays.asList(args));\n    if (Files.exists(Paths.get(javaHome, \"jmods\"))) {\n      argVals.addAll(\n          1,\n          Arrays.asList(\"--add-exports\", \"jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"));\n    }\n    ProcessBuilder pb = new ProcessBuilder(argVals);\n\n    pb.environment().remove(\"JAVA_TOOL_OPTIONS\");\n    Process p = pb.start();\n\n    CountDownLatch l = new CountDownLatch(checkLines);\n\n    new Thread(\n            () -> {\n              try {\n                BufferedReader br =\n                    new BufferedReader(\n                        new InputStreamReader(p.getErrorStream(), StandardCharsets.UTF_8));\n\n                String line = null;\n                while ((line = br.readLine()) != null) {\n                  System.out.println(\"[btrace err] \" + line);\n                  if (line.contains(\"Server VM warning\")\n                      || line.contains(\"XML libraries not available\")\n                      || line.contains(\"Connection reset\")) {\n                    // skip JVM generated warnings\n                    continue;\n                  }\n                  if (line.startsWith(\"[traced app]\") || line.startsWith(\"[btrace out]\")) {\n                    // skip test debug lines\n                    continue;\n                  }\n                  stderr.append(line).append('\\n');\n                  if (line.contains(\"Exception\") || line.contains(\"Error\")) {\n                    for (int i = 0; i < checkLines; i++) {\n                      l.countDown();\n                    }\n                  }\n                }\n              } catch (Exception e) {\n                for (int i = 0; i < checkLines; i++) {\n                  l.countDown();\n                }\n                throw new Error(e);\n              }\n            },\n            \"Stderr Reader\")\n        .start();\n\n    new Thread(\n            () -> {\n              try {\n                BufferedReader br =\n                    new BufferedReader(\n                        new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8));\n                String line = null;\n                while ((line = br.readLine()) != null) {\n                  stdout.append(line).append('\\n');\n                  System.out.println(\"[btrace out] \" + line);\n                  if (!(debugBTrace && line.contains(\"DEBUG:\"))) {\n                    l.countDown();\n                  }\n                }\n              } catch (Exception e) {\n                for (int i = 0; i < checkLines; i++) {\n                  l.countDown();\n                }\n                throw new Error(e);\n              }\n            },\n            \"Stdout Reader\")\n        .start();\n\n    l.await(timeout, TimeUnit.MILLISECONDS);\n\n    // Thread.sleep(100_000_000L);\n\n    return p;\n  }\n\n  public File locateTrace(String trace) {\n//    Path start = projectRoot.resolve(\"src\");\n    List<Path> roots = new ArrayList<>();\n    if (trace.toLowerCase().endsWith(\".java\")) {\n      roots.add(projectRoot.resolve(\"src\"));\n    } else {\n      roots.add(projectRoot.resolve(\"../btrace-instr/build/classes\"));\n      roots.add(projectRoot.resolve(\"build/classes\"));\n    }\n    Path[] tracePath = new Path[1];\n    for (Path start : roots) {\n      try {\n        Files.walkFileTree(\n                start,\n                new FileVisitor<Path>() {\n                  @Override\n                  public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)\n                          throws IOException {\n                    return FileVisitResult.CONTINUE;\n                  }\n\n                  @Override\n                  public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)\n                          throws IOException {\n                    if (file.toString().endsWith(trace)) {\n                      tracePath[0] = file;\n                      return FileVisitResult.TERMINATE;\n                    }\n                    return FileVisitResult.CONTINUE;\n                  }\n\n                  @Override\n                  public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {\n                    return FileVisitResult.TERMINATE;\n                  }\n\n                  @Override\n                  public FileVisitResult postVisitDirectory(Path dir, IOException exc)\n                          throws IOException {\n                    return FileVisitResult.CONTINUE;\n                  }\n                });\n      } catch(IOException e){\n        e.printStackTrace();\n      }\n      if (tracePath[0] != null) {\n        return tracePath[0].toFile();\n      }\n    }\n    return null;\n  }\n\n  private Process attach(\n      String pid,\n      String trace,\n      String[] cmdArgs,\n      int checkLines,\n      StringBuilder stdout,\n      StringBuilder stderr)\n      throws Exception {\n    File traceFile = locateTrace(trace);\n    List<String> argVals =\n        new ArrayList<>(\n            Arrays.asList(\n                javaHome + \"/bin/java\",\n                \"-Dcom.sun.btrace.unsafe=\" + isUnsafe,\n                \"-Dcom.sun.btrace.debug=\" + debugBTrace,\n                \"-Dcom.sun.btrace.trackRetransforms=\" + trackRetransforms,\n                \"-Dbtrace.comm.protocol=2\",\n                \"-Dbtrace.comm.autoNegotiate=false\",\n                \"-Dbtrace.comm.forceVersion=true\",\n                \"-Dbtrace.libs=\" + System.getProperty(\"btrace.libs\"),\n                \"-cp\",\n                cp,\n                \"org.openjdk.btrace.boot.Loader\",\n                \"-cp\",\n                eventsClassPath,\n                \"-d\",\n                Paths.get(System.getProperty(\"java.io.tmpdir\"), \"btrace-test\").toString(),\n                \"-pd\",\n                traceFile.getParentFile().getAbsolutePath()));\n    if (debugBTrace) {\n      argVals.add(\"-v\");\n    }\n    if (dumpOneliner) {\n      int cpIdx = argVals.indexOf(\"-cp\");\n      if (cpIdx > -1) {\n        argVals.add(cpIdx, \"-Dbtrace.oneliner.dump=true\");\n      }\n    }\n    if (unattended) {\n      argVals.add(\"-x\");\n    }\n    if (btracePort > 0) {\n      argVals.add(\"-p\");\n      argVals.add(String.valueOf(btracePort));\n    }\n    argVals.addAll(Arrays.asList(pid, traceFile.getAbsolutePath()));\n    if (cmdArgs != null) {\n      argVals.addAll(Arrays.asList(cmdArgs));\n    }\n    if (Files.exists(Paths.get(javaHome, \"jmods\"))) {\n      argVals.addAll(\n          1,\n          Arrays.asList(\"--add-exports\", \"jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"));\n    }\n    ProcessBuilder pb = new ProcessBuilder(argVals);\n\n    pb.environment().remove(\"JAVA_TOOL_OPTIONS\");\n    Process p = pb.start();\n\n    CountDownLatch l = new CountDownLatch(checkLines);\n\n    new Thread(\n            () -> {\n              try {\n                BufferedReader br =\n                    new BufferedReader(\n                        new InputStreamReader(p.getErrorStream(), StandardCharsets.UTF_8));\n\n                String line = null;\n                while ((line = br.readLine()) != null) {\n                  System.out.println(\"[btrace err] \" + line);\n                  if (line.contains(\"Server VM warning\")\n                      || line.contains(\"XML libraries not available\")\n                      || line.contains(\"Connection reset\")) {\n                    // skip JVM generated warnings\n                    continue;\n                  }\n                  if (line.startsWith(\"[traced app]\") || line.startsWith(\"[btrace out]\")) {\n                    // skip test debug lines\n                    continue;\n                  }\n                  stderr.append(line).append('\\n');\n                  if (line.contains(\"Exception\") || line.contains(\"Error\")) {\n                    for (int i = 0; i < checkLines; i++) {\n                      l.countDown();\n                    }\n                  }\n                }\n              } catch (Exception e) {\n                for (int i = 0; i < checkLines; i++) {\n                  l.countDown();\n                }\n                throw new Error(e);\n              }\n            },\n            \"Stderr Reader\")\n        .start();\n\n    new Thread(\n            () -> {\n              try {\n                BufferedReader br =\n                    new BufferedReader(\n                        new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8));\n                String line = null;\n                while ((line = br.readLine()) != null) {\n                  stdout.append(line).append('\\n');\n                  System.out.println(\"[btrace out] \" + line);\n                  if (!(debugBTrace && line.contains(\"DEBUG\"))) {\n                    l.countDown();\n                  }\n                }\n              } catch (Exception e) {\n                for (int i = 0; i < checkLines; i++) {\n                  l.countDown();\n                }\n                throw new Error(e);\n              }\n            },\n            \"Stdout Reader\")\n        .start();\n\n    l.await(timeout, TimeUnit.MILLISECONDS);\n\n    // Thread.sleep(100_000_000L);\n\n    return p;\n  }\n\n  private Process attachOneliner(\n      String pid,\n      String oneliner,\n      String[] cmdArgs,\n      int checkLines,\n      StringBuilder stdout,\n      StringBuilder stderr)\n      throws Exception {\n    List<String> argVals =\n        new ArrayList<>(\n            Arrays.asList(\n                javaHome + \"/bin/java\",\n                \"-Dcom.sun.btrace.unsafe=\" + isUnsafe,\n                \"-Dcom.sun.btrace.debug=\" + debugBTrace,\n                \"-Dcom.sun.btrace.trackRetransforms=\" + trackRetransforms,\n                \"-Dbtrace.comm.protocol=2\",\n                \"-Dbtrace.comm.autoNegotiate=false\",\n                \"-Dbtrace.comm.forceVersion=true\",\n                \"-cp\",\n                cp,\n                \"org.openjdk.btrace.boot.Loader\",\n                \"-cp\",\n                eventsClassPath,\n                \"-d\",\n                Paths.get(System.getProperty(\"java.io.tmpdir\"), \"btrace-test\").toString(),\n                \"-n\",\n                oneliner,\n                \"-pd\",\n                Paths.get(System.getProperty(\"java.io.tmpdir\"), \"btrace-oneliner\").toString()));\n    if (debugBTrace) {\n      argVals.add(\"-v\");\n    }\n    if (unattended) {\n      argVals.add(\"-x\");\n    }\n    if (btracePort > 0) {\n      argVals.add(\"-p\");\n      argVals.add(String.valueOf(btracePort));\n    }\n    argVals.addAll(Arrays.asList(pid));\n    if (cmdArgs != null) {\n      argVals.addAll(Arrays.asList(cmdArgs));\n    }\n    if (Files.exists(Paths.get(javaHome, \"jmods\"))) {\n      argVals.addAll(\n          1,\n          Arrays.asList(\"--add-exports\", \"jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED\"));\n    }\n    ProcessBuilder pb = new ProcessBuilder(argVals);\n\n    pb.environment().remove(\"JAVA_TOOL_OPTIONS\");\n    Process p = pb.start();\n\n    CountDownLatch l = new CountDownLatch(checkLines);\n\n    new Thread(\n            () -> {\n              try {\n                BufferedReader br =\n                    new BufferedReader(\n                        new InputStreamReader(p.getErrorStream(), StandardCharsets.UTF_8));\n\n                String line = null;\n                while ((line = br.readLine()) != null) {\n                  System.out.println(\"[btrace err] \" + line);\n                  if (line.contains(\"Server VM warning\")\n                      || line.contains(\"XML libraries not available\")\n                      || line.contains(\"Successfully started BTrace probe\")\n                      || line.contains(\"Connection reset\")\n                      || line.contains(\"terminally deprecated method in sun.misc.Unsafe\")\n                      || line.contains(\"sun.misc.Unsafe::objectFieldOffset\")\n                      || line.contains(\"org.jctools.util.UnsafeAccess\")\n                      || line.contains(\"A restricted method\")) {\n                    // skip JVM generated warnings\n                    continue;\n                  }\n                  if (line.startsWith(\"[traced app]\") || line.startsWith(\"[btrace out]\")) {\n                    // skip test debug lines\n                    continue;\n                  }\n                  stderr.append(line).append('\\n');\n                  if (line.contains(\"Exception\") || line.contains(\"Error\")) {\n                    for (int i = 0; i < checkLines; i++) {\n                      l.countDown();\n                    }\n                  }\n                }\n              } catch (Exception e) {\n                for (int i = 0; i < checkLines; i++) {\n                  l.countDown();\n                }\n                throw new Error(e);\n              }\n            },\n            \"Stderr Reader\")\n        .start();\n\n    new Thread(\n            () -> {\n              try {\n                BufferedReader br =\n                    new BufferedReader(\n                        new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8));\n                String line = null;\n                while ((line = br.readLine()) != null) {\n                  stdout.append(line).append('\\n');\n                  System.out.println(\"[btrace out] \" + line);\n                  if (!(debugBTrace && line.contains(\"DEBUG\"))) {\n                    l.countDown();\n                  }\n                }\n              } catch (Exception e) {\n                for (int i = 0; i < checkLines; i++) {\n                  l.countDown();\n                }\n                throw new Error(e);\n              }\n            },\n            \"Stdout Reader\")\n        .start();\n\n    l.await(timeout, TimeUnit.MILLISECONDS);\n\n    return p;\n  }\n\n  protected int getBTracePort() {\n    return btracePort > 0 ? btracePort : Integer.getInteger(\"btrace.port\", 2020);\n  }\n\n  protected String getEventsClassPath() {\n    return eventsClassPath;\n  }\n\n  protected Client createClientForTests(String probeDescPath) {\n    String libs = System.getProperty(\"btrace.libs\");\n    String agentJar = null;\n    String bootJar = null;\n\n    if (libs != null) {\n      // First check for new masked btrace.jar structure\n      Path maskedJar = Paths.get(libs, \"btrace.jar\");\n      if (Files.exists(maskedJar)) {\n        // Use masked JAR - pass it as agent, boot is embedded\n        agentJar = maskedJar.toString();\n        bootJar = null; // boot classes are in the masked JAR\n      } else {\n        // Fall back to old separate JAR structure\n        agentJar = Paths.get(libs, \"btrace-agent.jar\").toString();\n        bootJar = Paths.get(libs, \"btrace-boot.jar\").toString();\n      }\n    }\n\n    return new Client(\n        getBTracePort(),\n        null,\n        probeDescPath,\n        debugBTrace,\n        trackRetransforms,\n        false,\n        false,\n        null,\n        null,\n        agentJar,\n        bootJar);\n  }\n\n  protected List<String> listProbesWithProtocol(String host) throws IOException {\n    int port = getBTracePort();\n    try (Socket socket = new Socket(host, port);\n        WireProtocol protocol = createClientProtocol(socket, host)) {\n      ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n      if (config.isForceVersion()\n          && config.getVersion() == ProtocolVersion.V2\n          && !(protocol instanceof BinaryWireProtocol)) {\n        throw new IOException(\"Expected V2 protocol but got: \" + protocol.getClass().getName());\n      }\n      protocol.write(new ListProbesCommand());\n      Command cmd = protocol.read();\n      if (cmd instanceof ListProbesCommand) {\n        return ((ListProbesCommand) cmd).getProbes();\n      }\n      return Collections.emptyList();\n    } catch (ClassNotFoundException e) {\n      throw new IOException(e);\n    }\n  }\n\n  private WireProtocol createClientProtocol(Socket socket, String host) throws IOException {\n    ProtocolConfig config = ProtocolConfig.fromSystemProperties();\n    ProtocolVersion preferred = config.getVersion();\n\n    if (config.isAutoNegotiate() && preferred == ProtocolVersion.V2) {\n      try {\n        return createV2Protocol(socket);\n      } catch (IOException e) {\n        closeSocketQuietly(socket);\n        Socket fallback = new Socket(host, getBTracePort());\n        return createV1Protocol(fallback);\n      }\n    }\n\n    if (config.isForceVersion() && preferred == ProtocolVersion.V2) {\n      return createV2Protocol(socket);\n    }\n\n    return createV1Protocol(socket);\n  }\n\n  private WireProtocol createV1Protocol(Socket socket) throws IOException {\n    InputStream in = socket.getInputStream();\n    OutputStream out = socket.getOutputStream();\n    return new JavaSerializationProtocol(in, out);\n  }\n\n  private WireProtocol createV2Protocol(Socket socket) throws IOException {\n    InputStream in = socket.getInputStream();\n    OutputStream out = socket.getOutputStream();\n    ProtocolNegotiator negotiator = new ProtocolNegotiator(ProtocolVersion.V2);\n    int timeoutMs = ProtocolNegotiator.getNegotiationTimeoutMs();\n    int previousTimeout = socket.getSoTimeout();\n    try {\n      socket.setSoTimeout(timeoutMs);\n      ProtocolVersion negotiated = negotiator.negotiateClient(in, out, ProtocolVersion.V2);\n      if (negotiated != ProtocolVersion.V2) {\n        throw new IOException(\"Protocol negotiation failed: expected V2\");\n      }\n      return new BinaryWireProtocol(in, out);\n    } finally {\n      socket.setSoTimeout(previousTimeout);\n    }\n  }\n\n  private void closeSocketQuietly(Socket socket) {\n    if (socket == null) {\n      return;\n    }\n    try {\n      socket.close();\n    } catch (IOException ignore) {\n      // best effort\n    }\n  }\n\n  public interface ResultValidator {\n    void validate(String stdout, String stderr, int retcode, String jfrFile);\n  }\n}\n"
  },
  {
    "path": "integration-tests/src/test/resources/META-INF/btrace/permissions.properties",
    "content": "allowPrivileged=true"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:recommended\",\n    \":semanticCommits\",\n    \"group:allNonMajor\"\n  ],\n  \"baseBranches\": [\"develop\"],\n  \"schedule\": [\"before 9am on monday\"],\n  \"labels\": [\"dependencies\"],\n  \"packageRules\": [\n    {\n      \"matchManagers\": [\"github-actions\"],\n      \"additionalLabels\": [\"github-actions\"]\n    },\n    {\n      \"matchUpdateTypes\": [\"minor\", \"patch\"],\n      \"automerge\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "run_tests.sh",
    "content": "#! /bin/bash\n\nset -e\n\nexport JAVA_HOME=$JAVA_8_HOME\necho \"Building BTrace binary artifacts\"\n./gradlew -x test :btrace-dist:build\n\nmkdir -p build/reports\nfor VERSION in 8 11 17 18 19 20; do\n  declare home_string=JAVA_${VERSION}_HOME\n  if [ -z \"${!home_string}\" ]; then\n    echo \"Skipping test for Java ${VERSINO}\"\n    continue\n  fi\n  echo \"Running tests with TEST_JAVA_HOME=${!home_string}\"\n  TEST_JAVA_HOME=${!home_string} BTRACE_TEST_DEBUG=\"false\" ./gradlew -Pintegration test | tee -a build/reports/test_java_$VERSION.out  || true\ndone\n"
  },
  {
    "path": "scripts/release.sh",
    "content": "#!/usr/bin/env bash\n#\n# BTrace Release Script\n#\n# This script validates release parameters and triggers the GitHub Actions\n# release workflow via the gh CLI.\n#\n# Usage:\n#   ./scripts/release.sh <major|minor|patch> [commit-or-branch]\n#\n# Examples:\n#   ./scripts/release.sh minor                    # Minor release from develop\n#   ./scripts/release.sh major                    # Major release from develop\n#   ./scripts/release.sh patch release/2.3._      # Patch release from release/2.3._\n#\n# Environment variables:\n#   DRY_RUN=true    Show what would be done without triggering workflow\n#\n\nset -euo pipefail\n\n# Colors for output\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nNC='\\033[0m' # No Color\n\n# Script directory and project root\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_ROOT=\"$(cd \"${SCRIPT_DIR}/..\" && pwd)\"\n\n# Configuration\nGRADLE_VERSION_FILE=\"${PROJECT_ROOT}/common.gradle\"\nDRY_RUN=\"${DRY_RUN:-false}\"\n\n#######################################\n# Print colored message\n#######################################\ninfo() {\n    echo -e \"${BLUE}[INFO]${NC} $*\"\n}\n\nsuccess() {\n    echo -e \"${GREEN}[SUCCESS]${NC} $*\"\n}\n\nwarn() {\n    echo -e \"${YELLOW}[WARN]${NC} $*\"\n}\n\nerror() {\n    echo -e \"${RED}[ERROR]${NC} $*\" >&2\n}\n\n#######################################\n# Print usage information\n#######################################\nusage() {\n    cat <<EOF\nBTrace Release Script\n\nUsage:\n  $(basename \"$0\") <release-type> [source-ref]\n\nArguments:\n  release-type    Type of release: major, minor, or patch\n  source-ref      Git reference (branch/commit) to release from (optional)\n                  - For major/minor: defaults to 'develop'\n                  - For patch: must be a release/X.Y branch\n                  - If omitted in interactive mode, shows a commit picker\n\nRelease Types:\n  major   Bump major version (e.g., 2.3.0-SNAPSHOT -> 3.0.0)\n          Next develop: 3.1.0-SNAPSHOT\n          Creates: release/3.0._ branch\n\n  minor   Release current version (e.g., 2.3.0-SNAPSHOT -> 2.3.0)\n          Next develop: 2.4.0-SNAPSHOT\n          Creates: release/2.3._ branch\n\n  patch   Bump patch version on release branch (e.g., 2.3.1-SNAPSHOT -> 2.3.1)\n          Next release branch: 2.3.2-SNAPSHOT\n          Requires: release/X.Y._ branch as source\n\nExamples:\n  $(basename \"$0\") minor                    # Release 2.3.0 from develop\n  $(basename \"$0\") major                    # Release 3.0.0 from develop\n  $(basename \"$0\") patch release/2.3._      # Release 2.3.1 from release/2.3._\n\nEnvironment:\n  DRY_RUN=true    Show what would happen without triggering the workflow\n\nEOF\n    exit 1\n}\n\n#######################################\n# Check if we have an interactive terminal\n#######################################\nis_interactive() {\n    [[ -t 0 && -t 1 ]]\n}\n\n#######################################\n# Check if fzf is available\n#######################################\nhas_fzf() {\n    command -v fzf &> /dev/null\n}\n\n#######################################\n# Display commit picker with master-detail view\n# Args: branch [count]\n# Returns: selected commit SHA or branch name\n#######################################\npick_commit() {\n    local branch=$1\n    local count=${2:-20}\n\n    # Build list of commits with more detail\n    local commits\n    commits=$(git log \"${branch}\" --format=\"%h  %ad  %s\" --date=short -n \"${count}\" 2>/dev/null)\n\n    if [[ -z \"${commits}\" ]]; then\n        error \"No commits found on branch '${branch}'\"\n        exit 1\n    fi\n\n    echo \"\" >&2\n    echo -e \"${BLUE}Select commit for release from '${branch}':${NC}\" >&2\n    echo \"\" >&2\n\n    if has_fzf; then\n        # Use fzf with preview pane for master-detail view\n        local header_line=\"HEAD      (latest)  Use latest commit on ${branch}\"\n\n        # Preview command shows full commit details\n        # For HEAD line, show branch tip; for commits, show the specific commit\n        local preview_cmd='\n            line={}\n            sha=$(echo \"$line\" | awk \"{print \\$1}\")\n            if [[ \"$sha\" == \"HEAD\" ]]; then\n                git log -1 --format=\"Commit:  %H%nAuthor:  %an <%ae>%nDate:    %ad%n%nSubject: %s%n%n%b\" --date=format:\"%Y-%m-%d %H:%M:%S\" '\"${branch}\"'\n                echo \"\"\n                echo \"─── Changed Files ───\"\n                git diff-tree --no-commit-id --name-status -r '\"${branch}\"' | head -20\n            else\n                git log -1 --format=\"Commit:  %H%nAuthor:  %an <%ae>%nDate:    %ad%nTags:    %(describe:tags)%n%nSubject: %s%n%n%b\" --date=format:\"%Y-%m-%d %H:%M:%S\" \"$sha\" 2>/dev/null\n                echo \"\"\n                echo \"─── Changed Files ───\"\n                git diff-tree --no-commit-id --name-status -r \"$sha\" 2>/dev/null | head -20\n            fi\n        '\n\n        local selected\n        selected=$(echo -e \"${header_line}\\n${commits}\" | \\\n            fzf --height=80% \\\n                --reverse \\\n                --header=\"↑/↓: navigate  Enter: select  Esc: cancel\" \\\n                --preview=\"${preview_cmd}\" \\\n                --preview-window=right:50%:wrap \\\n                --ansi \\\n                2>/dev/tty)\n\n        if [[ -z \"${selected}\" ]]; then\n            error \"No commit selected\"\n            exit 1\n        fi\n\n        # If selected the HEAD option, return branch name\n        if [[ \"${selected}\" == \"${header_line}\" ]]; then\n            echo \"${branch}\"\n        else\n            # Extract SHA from selected line\n            echo \"${selected}\" | awk '{print $1}'\n        fi\n    else\n        # Fallback to numbered selection (no fzf available)\n        echo -e \"${YELLOW}Tip: Install fzf for a better interactive experience with preview${NC}\" >&2\n        echo -e \"${YELLOW}     brew install fzf  OR  apt install fzf  OR  https://github.com/junegunn/fzf${NC}\" >&2\n        echo \"\" >&2\n        echo -e \"  ${GREEN}1)${NC} ${branch} (HEAD)         Use latest commit on ${branch}\" >&2\n        echo \"  ─────────────────────────────────────────────────────\" >&2\n\n        local i=2\n        local -a commit_shas\n        commit_shas=(\"${branch}\")  # Index 1 is the branch HEAD\n\n        while IFS= read -r line; do\n            local sha date subject\n            sha=$(echo \"${line}\" | awk '{print $1}')\n            date=$(echo \"${line}\" | awk '{print $2}')\n            subject=$(echo \"${line}\" | cut -d' ' -f3-)\n            # Truncate subject if too long\n            if [[ ${#subject} -gt 50 ]]; then\n                subject=\"${subject:0:47}...\"\n            fi\n            echo -e \"  ${GREEN}${i})${NC} ${sha}  ${date}   ${subject}\" >&2\n            commit_shas+=(\"${sha}\")\n            ((i++))\n        done <<< \"${commits}\"\n\n        echo \"\" >&2\n        local max=$((i - 1))\n        local selection\n\n        while true; do\n            read -p \"Enter selection [1-${max}]: \" selection </dev/tty\n            if [[ \"${selection}\" =~ ^[0-9]+$ ]] && [[ \"${selection}\" -ge 1 ]] && [[ \"${selection}\" -le \"${max}\" ]]; then\n                break\n            fi\n            echo \"Invalid selection. Please enter a number between 1 and ${max}.\" >&2\n        done\n\n        echo \"${commit_shas[$((selection - 1))]}\"\n    fi\n}\n\n#######################################\n# Display branch picker for patch releases with preview\n# Returns: selected branch name (e.g., \"release/2.3\")\n#######################################\npick_release_branch() {\n    # Get release branches sorted by version (newest first)\n    local branches\n    branches=$(git branch -a --list '*release/*' | sed 's/.*\\(release\\/[0-9]*\\.[0-9]*\\._\\).*/\\1/' | sort -t. -k1,1nr -k2,2nr | uniq)\n\n    if [[ -z \"${branches}\" ]]; then\n        error \"No release branches found (expected pattern: release/X.Y._)\"\n        exit 1\n    fi\n\n    echo \"\" >&2\n    echo -e \"${BLUE}Select release branch:${NC}\" >&2\n    echo \"\" >&2\n\n    if has_fzf; then\n        # Build display list with latest tag info\n        local display_list=\"\"\n        while IFS= read -r branch; do\n            local latest_tag\n            latest_tag=$(git describe --tags --abbrev=0 \"${branch}\" 2>/dev/null || echo \"no releases\")\n            display_list+=\"${branch}   (latest: ${latest_tag})\"$'\\n'\n        done <<< \"${branches}\"\n\n        # Preview command shows branch info and recent commits\n        local preview_cmd='\n            branch=$(echo {} | awk \"{print \\$1}\")\n            echo \"Branch: $branch\"\n            echo \"\"\n            latest_tag=$(git describe --tags --abbrev=0 \"$branch\" 2>/dev/null || echo \"none\")\n            current_ver=$(git show \"$branch:common.gradle\" 2>/dev/null | grep \"project.version\" | sed -E \"s/.*\\x27([^\\x27]+)\\x27.*/\\1/\")\n            echo \"Latest tag:      $latest_tag\"\n            echo \"Current version: $current_ver\"\n            echo \"\"\n            echo \"─── Recent Commits ───\"\n            git log \"$branch\" --oneline -10 2>/dev/null\n            echo \"\"\n            echo \"─── Release Tags ───\"\n            git tag --list \"v${branch#release/}.*\" --sort=-version:refname | head -5\n        '\n\n        local selected\n        selected=$(echo -e \"${display_list}\" | \\\n            fzf --height=60% \\\n                --reverse \\\n                --header=\"↑/↓: navigate  Enter: select  Esc: cancel\" \\\n                --preview=\"${preview_cmd}\" \\\n                --preview-window=right:50%:wrap \\\n                2>/dev/tty)\n\n        if [[ -z \"${selected}\" ]]; then\n            error \"No branch selected\"\n            exit 1\n        fi\n\n        # Extract branch name\n        echo \"${selected}\" | awk '{print $1}'\n    else\n        # Fallback to numbered selection (no fzf available)\n        echo -e \"${YELLOW}Tip: Install fzf for a better interactive experience with preview${NC}\" >&2\n        echo -e \"${YELLOW}     brew install fzf  OR  apt install fzf  OR  https://github.com/junegunn/fzf${NC}\" >&2\n        echo \"\" >&2\n\n        local i=1\n        local -a branch_names\n\n        while IFS= read -r branch; do\n            local latest_tag\n            latest_tag=$(git describe --tags --abbrev=0 \"${branch}\" 2>/dev/null || echo \"no releases\")\n            echo -e \"  ${GREEN}${i})${NC} ${branch}   (latest: ${latest_tag})\" >&2\n            branch_names+=(\"${branch}\")\n            ((i++))\n        done <<< \"${branches}\"\n\n        echo \"\" >&2\n        local max=$((i - 1))\n        local selection\n\n        while true; do\n            read -p \"Enter selection [1-${max}]: \" selection </dev/tty\n            if [[ \"${selection}\" =~ ^[0-9]+$ ]] && [[ \"${selection}\" -ge 1 ]] && [[ \"${selection}\" -le \"${max}\" ]]; then\n                break\n            fi\n            echo \"Invalid selection. Please enter a number between 1 and ${max}.\" >&2\n        done\n\n        echo \"${branch_names[$((selection - 1))]}\"\n    fi\n}\n\n#######################################\n# Check prerequisites\n#######################################\ncheck_prerequisites() {\n    info \"Checking prerequisites...\"\n\n    # Check gh CLI is installed\n    if ! command -v gh &> /dev/null; then\n        error \"GitHub CLI (gh) is not installed.\"\n        error \"Install it from: https://cli.github.com/\"\n        exit 1\n    fi\n\n    # Check gh is authenticated\n    if ! gh auth status &> /dev/null; then\n        error \"GitHub CLI is not authenticated.\"\n        error \"Run: gh auth login\"\n        exit 1\n    fi\n\n    # Check we're in a git repository\n    if ! git rev-parse --git-dir &> /dev/null; then\n        error \"Not in a git repository.\"\n        exit 1\n    fi\n\n    # Check working directory is clean\n    if [[ -n \"$(git status --porcelain)\" ]]; then\n        error \"Working directory is not clean.\"\n        error \"Please commit or stash your changes before releasing.\"\n        exit 1\n    fi\n\n    # Check common.gradle exists\n    if [[ ! -f \"${GRADLE_VERSION_FILE}\" ]]; then\n        error \"Cannot find ${GRADLE_VERSION_FILE}\"\n        exit 1\n    fi\n\n    success \"All prerequisites met.\"\n}\n\n#######################################\n# Extract current version from common.gradle\n#######################################\nget_current_version() {\n    local version_line\n    version_line=$(grep \"project.version\" \"${GRADLE_VERSION_FILE}\" | head -1)\n\n    if [[ -z \"${version_line}\" ]]; then\n        error \"Cannot find version in ${GRADLE_VERSION_FILE}\"\n        exit 1\n    fi\n\n    # Extract version from line like: project.version = '2.3.0-SNAPSHOT'\n    echo \"${version_line}\" | sed -E \"s/.*'([^']+)'.*/\\1/\"\n}\n\n#######################################\n# Parse version components\n# Args: version string (e.g., \"2.3.0-SNAPSHOT\")\n# Outputs: major minor patch is_snapshot\n#######################################\nparse_version() {\n    local version=$1\n    local base_version=\"${version%-SNAPSHOT}\"\n    local is_snapshot=\"false\"\n\n    if [[ \"${version}\" == *\"-SNAPSHOT\" ]]; then\n        is_snapshot=\"true\"\n    fi\n\n    # Split by dots\n    IFS='.' read -r major minor patch <<< \"${base_version}\"\n\n    echo \"${major} ${minor} ${patch:-0} ${is_snapshot}\"\n}\n\n#######################################\n# Calculate release versions\n# Args: release_type current_version\n# Outputs: release_version next_develop_snapshot next_release_snapshot release_branch\n#######################################\ncalculate_versions() {\n    local release_type=$1\n    local current_version=$2\n\n    read -r major minor patch is_snapshot <<< \"$(parse_version \"${current_version}\")\"\n\n    local release_version=\"\"\n    local next_develop_snapshot=\"\"\n    local next_release_snapshot=\"\"\n    local release_branch=\"\"\n\n    case \"${release_type}\" in\n        major)\n            # Major: X.Y.Z-SNAPSHOT -> (X+1).0.0\n            release_version=\"$((major + 1)).0.0\"\n            next_develop_snapshot=\"$((major + 1)).1.0-SNAPSHOT\"\n            next_release_snapshot=\"$((major + 1)).0.1-SNAPSHOT\"\n            release_branch=\"release/$((major + 1)).0._\"\n            ;;\n        minor)\n            # Minor: X.Y.Z-SNAPSHOT -> X.Y.0 (always .0 for minor releases)\n            release_version=\"${major}.${minor}.0\"\n            next_develop_snapshot=\"${major}.$((minor + 1)).0-SNAPSHOT\"\n            next_release_snapshot=\"${major}.${minor}.1-SNAPSHOT\"\n            release_branch=\"release/${major}.${minor}._\"\n            ;;\n        patch)\n            # Patch: X.Y.Z-SNAPSHOT -> X.Y.Z\n            release_version=\"${major}.${minor}.${patch}\"\n            next_develop_snapshot=\"\"  # Not updated for patch releases\n            next_release_snapshot=\"${major}.${minor}.$((patch + 1))-SNAPSHOT\"\n            release_branch=\"release/${major}.${minor}._\"\n            ;;\n        *)\n            error \"Invalid release type: ${release_type}\"\n            exit 1\n            ;;\n    esac\n\n    echo \"${release_version} ${next_develop_snapshot} ${next_release_snapshot} ${release_branch}\"\n}\n\n#######################################\n# Validate source reference for release type\n#######################################\nvalidate_source_ref() {\n    local release_type=$1\n    local source_ref=$2\n\n    info \"Validating source reference: ${source_ref}\"\n\n    # Check if reference exists\n    if ! git rev-parse --verify \"${source_ref}\" &> /dev/null; then\n        error \"Reference '${source_ref}' does not exist.\"\n        exit 1\n    fi\n\n    case \"${release_type}\" in\n        major|minor)\n            # Must be from develop or a commit reachable from develop\n            if [[ \"${source_ref}\" != \"develop\" ]]; then\n                if ! git merge-base --is-ancestor \"${source_ref}\" develop 2>/dev/null; then\n                    # Check if develop is ancestor of source_ref\n                    if ! git merge-base --is-ancestor develop \"${source_ref}\" 2>/dev/null; then\n                        warn \"Reference '${source_ref}' may not be reachable from develop.\"\n                    fi\n                fi\n            fi\n            ;;\n        patch)\n            # Must be from a release/X.Y._ branch or a commit from one\n            if [[ \"${source_ref}\" =~ ^release/[0-9]+\\.[0-9]+\\._$ ]]; then\n                # It's a branch name, check if it exists\n                if ! git show-ref --verify --quiet \"refs/heads/${source_ref}\" && \\\n                   ! git show-ref --verify --quiet \"refs/remotes/origin/${source_ref}\"; then\n                    error \"Release branch '${source_ref}' does not exist.\"\n                    exit 1\n                fi\n            elif [[ -n \"${SELECTED_RELEASE_BRANCH:-}\" ]]; then\n                # A commit SHA was selected from the picker, validate it's on the release branch\n                if ! git merge-base --is-ancestor \"${source_ref}\" \"${SELECTED_RELEASE_BRANCH}\" 2>/dev/null; then\n                    if ! git merge-base --is-ancestor \"${SELECTED_RELEASE_BRANCH}\" \"${source_ref}\" 2>/dev/null; then\n                        error \"Commit '${source_ref}' is not on branch '${SELECTED_RELEASE_BRANCH}'.\"\n                        exit 1\n                    fi\n                fi\n            else\n                error \"Patch releases must be from a release/X.Y._ branch.\"\n                error \"Got: ${source_ref}\"\n                exit 1\n            fi\n            ;;\n    esac\n\n    success \"Source reference validated.\"\n}\n\n#######################################\n# Check if tag already exists\n#######################################\ncheck_tag_exists() {\n    local tag=$1\n\n    if git rev-parse \"v${tag}\" &> /dev/null; then\n        error \"Tag v${tag} already exists.\"\n        exit 1\n    fi\n\n    # Also check remote\n    if git ls-remote --tags origin \"refs/tags/v${tag}\" | grep -q .; then\n        error \"Tag v${tag} already exists on remote.\"\n        exit 1\n    fi\n\n    # Check for leftover RC tag (locally and on remote)\n    if git rev-parse \"v${tag}_RC\" &> /dev/null; then\n        error \"RC tag v${tag}_RC already exists locally.\"\n        error \"Clean up with: git tag -d v${tag}_RC\"\n        exit 1\n    fi\n\n    if git ls-remote --tags origin \"refs/tags/v${tag}_RC\" | grep -q .; then\n        error \"RC tag v${tag}_RC already exists on remote.\"\n        error \"Clean up with: git push origin :refs/tags/v${tag}_RC && git tag -d v${tag}_RC\"\n        exit 1\n    fi\n}\n\n#######################################\n# Get commit SHA for reference\n#######################################\nget_commit_sha() {\n    local ref=$1\n    git rev-parse \"${ref}\"\n}\n\n#######################################\n# Display release summary and confirm\n#######################################\nconfirm_release() {\n    local release_type=$1\n    local source_ref=$2\n    local release_version=$3\n    local next_develop=$4\n    local next_release=$5\n    local release_branch=$6\n    local commit_sha=$7\n\n    echo \"\"\n    echo \"========================================\"\n    echo \"          RELEASE SUMMARY\"\n    echo \"========================================\"\n    echo \"\"\n    echo -e \"  Release Type:     ${GREEN}${release_type}${NC}\"\n    echo -e \"  Source:           ${BLUE}${source_ref}${NC}\"\n    echo -e \"  Commit:           ${commit_sha:0:12}\"\n    echo \"\"\n    echo -e \"  Release Version:  ${GREEN}v${release_version}${NC}\"\n    echo -e \"  Release Branch:   ${BLUE}${release_branch}${NC}\"\n    echo \"\"\n    if [[ -n \"${next_develop}\" ]]; then\n        echo -e \"  Next develop:     ${YELLOW}${next_develop}${NC}\"\n    fi\n    echo -e \"  Next release:     ${YELLOW}${next_release}${NC}\"\n    echo \"\"\n    echo \"========================================\"\n    echo \"\"\n\n    if [[ \"${DRY_RUN}\" == \"true\" ]]; then\n        warn \"DRY RUN MODE - No workflow will be triggered\"\n        echo \"\"\n        return 0\n    fi\n\n    read -p \"Do you want to proceed with this release? [y/N] \" -n 1 -r\n    echo \"\"\n\n    if [[ ! $REPLY =~ ^[Yy]$ ]]; then\n        info \"Release cancelled.\"\n        exit 0\n    fi\n}\n\n#######################################\n# Trigger GitHub Actions workflow\n#######################################\ntrigger_workflow() {\n    local release_type=$1\n    local release_version=$2\n    local commit_sha=$3\n    local release_branch=$4\n    local next_snapshot=$5\n\n    info \"Triggering release workflow...\"\n\n    local workflow_inputs=(\n        -f \"release_type=${release_type}\"\n        -f \"release_version=${release_version}\"\n        -f \"commit_sha=${commit_sha}\"\n        -f \"release_branch=${release_branch}\"\n        -f \"next_snapshot=${next_snapshot}\"\n    )\n\n    if [[ \"${DRY_RUN}\" == \"true\" ]]; then\n        echo \"\"\n        info \"Would run: gh workflow run release.yml ${workflow_inputs[*]}\"\n        echo \"\"\n        return 0\n    fi\n\n    if gh workflow run release.yml \"${workflow_inputs[@]}\"; then\n        success \"Workflow triggered successfully!\"\n        echo \"\"\n        info \"Monitor the release at:\"\n        echo \"  https://github.com/btraceio/btrace/actions/workflows/release.yml\"\n    else\n        error \"Failed to trigger workflow.\"\n        exit 1\n    fi\n}\n\n#######################################\n# Main function\n#######################################\nmain() {\n    # Parse arguments\n    if [[ $# -lt 1 ]]; then\n        usage\n    fi\n\n    local release_type=\"${1:-}\"\n    local source_ref=\"${2:-}\"\n\n    # Used to track the release branch when a commit is picked interactively\n    SELECTED_RELEASE_BRANCH=\"\"\n\n    # Handle help\n    if [[ \"${release_type}\" == \"-h\" || \"${release_type}\" == \"--help\" ]]; then\n        usage\n    fi\n\n    # Validate release type\n    case \"${release_type}\" in\n        major|minor|patch)\n            ;;\n        *)\n            error \"Invalid release type: ${release_type}\"\n            echo \"Valid types: major, minor, patch\"\n            exit 1\n            ;;\n    esac\n\n    # Set default source reference based on release type\n    if [[ -z \"${source_ref}\" ]]; then\n        if ! is_interactive; then\n            # Non-interactive: use defaults or error\n            case \"${release_type}\" in\n                major|minor)\n                    source_ref=\"develop\"\n                    ;;\n                patch)\n                    error \"Patch releases require a release branch.\"\n                    echo \"Usage: $(basename \"$0\") patch release/X.Y._\"\n                    exit 1\n                    ;;\n            esac\n        else\n            # Interactive: show picker\n            case \"${release_type}\" in\n                major|minor)\n                    source_ref=$(pick_commit \"develop\")\n                    ;;\n                patch)\n                    local branch\n                    branch=$(pick_release_branch)\n                    source_ref=$(pick_commit \"${branch}\")\n                    # If user selected branch HEAD, use the branch name\n                    if [[ \"${source_ref}\" != \"${branch}\" ]]; then\n                        # User selected a specific commit, but we still need to validate\n                        # against the branch pattern for patch releases\n                        info \"Selected commit ${source_ref} from ${branch}\"\n                    fi\n                    # Store the branch for later validation\n                    SELECTED_RELEASE_BRANCH=\"${branch}\"\n                    ;;\n            esac\n        fi\n    fi\n\n    # Change to project root\n    cd \"${PROJECT_ROOT}\"\n\n    # Run checks\n    check_prerequisites\n\n    # Get current version\n    info \"Reading version from common.gradle...\"\n    local current_version\n    current_version=$(get_current_version)\n    info \"Current version: ${current_version}\"\n\n    # Validate source reference\n    validate_source_ref \"${release_type}\" \"${source_ref}\"\n\n    # For patch releases, we need to get the version from the release branch/commit\n    if [[ \"${release_type}\" == \"patch\" ]]; then\n        # Get version from the source reference (branch or commit)\n        local version_source=\"${source_ref}\"\n        local branch_version\n        branch_version=$(git show \"${version_source}:common.gradle\" 2>/dev/null | grep \"project.version\" | sed -E \"s/.*'([^']+)'.*/\\1/\")\n        if [[ -n \"${branch_version}\" ]]; then\n            current_version=\"${branch_version}\"\n            if [[ -n \"${SELECTED_RELEASE_BRANCH:-}\" ]]; then\n                info \"Using version from ${SELECTED_RELEASE_BRANCH} (commit ${source_ref:0:8}): ${current_version}\"\n            else\n                info \"Using version from ${source_ref}: ${current_version}\"\n            fi\n        fi\n    fi\n\n    # Calculate versions\n    read -r release_version next_develop next_release release_branch <<< \"$(calculate_versions \"${release_type}\" \"${current_version}\")\"\n\n    # Check if tag already exists\n    check_tag_exists \"${release_version}\"\n\n    # Get commit SHA\n    local commit_sha\n    commit_sha=$(get_commit_sha \"${source_ref}\")\n\n    # Show summary and confirm\n    confirm_release \"${release_type}\" \"${source_ref}\" \"${release_version}\" \\\n                    \"${next_develop}\" \"${next_release}\" \"${release_branch}\" \"${commit_sha}\"\n\n    # Determine next snapshot for workflow (use next_release for patch, next_develop for major/minor)\n    local workflow_next_snapshot\n    if [[ \"${release_type}\" == \"patch\" ]]; then\n        workflow_next_snapshot=\"${next_release}\"\n    else\n        workflow_next_snapshot=\"${next_develop}\"\n    fi\n\n    # Trigger the workflow\n    trigger_workflow \"${release_type}\" \"${release_version}\" \"${commit_sha}\" \\\n                     \"${release_branch}\" \"${workflow_next_snapshot}\"\n\n    success \"Release process initiated!\"\n}\n\n# Run main function\nmain \"$@\"\n"
  },
  {
    "path": "scripts/update-jdk-versions.sh",
    "content": "#!/usr/bin/env bash\n#\n# Checks for newer JDK versions on SDKMan and updates workflow files.\n# Exit 0 = changes made, exit 1 = no changes needed, exit 2 = error.\n#\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"$0\")\" && pwd)\"\nREPO_ROOT=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"\n\nCONTINUOUS=\"$REPO_ROOT/.github/workflows/continuous.yml\"\nRELEASE=\"$REPO_ROOT/.github/workflows/release.yml\"\n\nSDKMAN_API=\"https://api.sdkman.io/2/candidates/java/linuxx64/versions/all\"\n\n# Portable in-place sed (works on both GNU and BSD sed)\nsed_i() {\n  local expr=$1; shift\n  for f in \"$@\"; do\n    sed -i.bak \"$expr\" \"$f\" && rm -f \"$f.bak\"\n  done\n}\n\necho \"Fetching SDKMan version list...\" >&2\nALL_VERSIONS=$(curl -sf \"$SDKMAN_API\") || {\n  echo \"ERROR: Failed to fetch SDKMan version list\" >&2\n  exit 2\n}\n\nVERSION_LIST=$(printf '%s' \"$ALL_VERSIONS\" | tr ',' '\\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')\n\n# Find the latest Temurin GA release for a given major version.\n# Handles both X.0.N-tem and bare X-tem identifiers.\nlatest_temurin_ga() {\n  local major=$1\n  printf '%s\\n' \"$VERSION_LIST\" | grep -E \"^${major}(\\\\.0\\\\.[0-9]+)?-tem$\" | sort -V | tail -1\n}\n\n# Find the latest OpenJDK EA build for a given major version.\nlatest_ea_open() {\n  local major=$1\n  printf '%s\\n' \"$VERSION_LIST\" | grep -E \"^${major}\\\\.ea\\\\.[0-9]+-open$\" | sort -t. -k3 -n | tail -1\n}\n\n# --- Extract current versions ---\n\n# Test matrix from continuous.yml (superset of release.yml)\nMATRIX_VERSIONS=$(grep 'java:.*\\[' \"$CONTINUOUS\" | head -1 \\\n  | sed 's/.*\\[//;s/\\].*//' | tr ',' '\\n' \\\n  | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')\n\n# Build JDK from the \"echo 'y' | sdk install java\" line\nBUILD_JDK=$(grep \"echo 'y' | sdk install java\" \"$CONTINUOUS\" | head -1 \\\n  | sed \"s/.*sdk install java //\" | tr -d \"[:space:]\")\n\n# --- Resolve and apply updates ---\n\nCHANGES=()\n\nfor ver in $MATRIX_VERSIONS; do\n  if [[ \"$ver\" =~ ^([0-9]+)(\\.0\\.[0-9]+)?-tem$ ]]; then\n    major=\"${BASH_REMATCH[1]}\"\n    latest=$(latest_temurin_ga \"$major\")\n    if [[ -n \"$latest\" && \"$latest\" != \"$ver\" ]]; then\n      CHANGES+=(\"$ver -> $latest\")\n      # Only replace on matrix lines to avoid substring matches (e.g. 25-tem inside 11.0.25-tem)\n      sed_i \"/java:.*\\[/s|${ver}|${latest}|g\" \"$CONTINUOUS\" \"$RELEASE\"\n    fi\n  elif [[ \"$ver\" =~ ^([0-9]+)\\.ea\\.([0-9]+)-open$ ]]; then\n    major=\"${BASH_REMATCH[1]}\"\n    latest=$(latest_ea_open \"$major\")\n    if [[ -n \"$latest\" && \"$latest\" != \"$ver\" ]]; then\n      CHANGES+=(\"$ver -> $latest\")\n      sed_i \"/java:.*\\[/s|${ver}|${latest}|g\" \"$CONTINUOUS\" \"$RELEASE\"\n    fi\n  fi\ndone\n\n# Update build JDK if stale\nif [[ -n \"$BUILD_JDK\" && \"$BUILD_JDK\" =~ ^([0-9]+) ]]; then\n  build_major=\"${BASH_REMATCH[1]}\"\n  latest_build=$(latest_temurin_ga \"$build_major\")\n  if [[ -n \"$latest_build\" && \"$latest_build\" != \"$BUILD_JDK\" ]]; then\n    CHANGES+=(\"build JDK: $BUILD_JDK -> $latest_build\")\n    sed_i \"s|sdk install java ${BUILD_JDK}|sdk install java ${latest_build}|g\" \"$CONTINUOUS\" \"$RELEASE\"\n  fi\nfi\n\n# --- Report results ---\n\nif [[ ${#CHANGES[@]} -eq 0 ]]; then\n  echo \"All JDK versions are up to date.\" >&2\n  exit 1\nfi\n\nfor change in \"${CHANGES[@]}\"; do\n  echo \"- $change\"\ndone\nexit 0\n"
  },
  {
    "path": "settings.gradle",
    "content": "// Use the in-repo Gradle plugin for extension authorship without needing a remote repository\npluginManagement {\n    includeBuild('btrace-gradle-plugin')\n}\n\nrootProject.name = 'btrace-ng'\n\n// Find the directories containing a \"build.gradle\" file in the root directory\n// of the project. That is, every directory containing a \"build.gradle\" will\n// be automatically the subproject of this project.\ndef subDirs = rootDir.listFiles(new FileFilter() {\n    boolean accept(File file) {\n        if (!file.isDirectory()) {\n            return false\n        }\n        if (file.name == 'buildSrc') {\n            return false\n        }\n        return new File(file, 'build.gradle').isFile()\n    }\n})\n\nsubDirs.each { File dir ->\n    if (dir.name == 'btrace-gradle-plugin') {\n        // This module is consumed as an included build via pluginManagement\n        // to provide the Gradle plugin. Do not include it as a subproject.\n        return\n    }\n    // Skip legacy, removed modules\n    if (dir.name in ['btrace-services', 'btrace-services-api', 'btrace-statsd']) {\n        return\n    }\n    if (dir.name.startsWith(\"btrace-\")) {\n        include dir.name\n    }\n}\n\ninclude \"integration-tests\"\ninclude \"benchmarks:agent-benchmark\"\ninclude \"benchmarks:runtime-benchmarks\"\n\n// Explicitly include nested extension modules\ninclude 'btrace-extensions'\ninclude 'btrace-extensions:btrace-metrics'\ninclude 'btrace-extensions:btrace-utils'\ninclude 'btrace-extensions:btrace-statsd'\n\ndependencyResolutionManagement {\n    versionCatalogs {\n        libs {\n            // Families...\n            version('asm', '9.9.1')\n            version('jmh', '1.37')\n            version('jmhGradlePlugin', '0.7.3')\n            version('slf4j', '1.7.36')\n            version('junit', '5.11.4')\n            version('testcontainers', '2.0.4')\n\n            // *** Gradle plugins ***\n            plugin ('spotless', 'com.diffplug.spotless').version('7.0.2')\n            plugin ('versioning', 'net.nemerosa.versioning').version('2.15.1')\n            plugin ('ospackage', 'com.netflix.nebula.ospackage').version('11.11.2')\n            plugin ('publish', 'io.github.gradle-nexus.publish-plugin').version('2.0.0')\n            plugin ('shadow', 'com.github.johnrengelman.shadow').version('8.1.1')\n            plugin ('sdkman-vendors', 'io.sdkman.vendors').version('3.0.0')\n            plugin ('foojay-resolver', 'org.gradle.toolchains.foojay-resolver-convention').version('1.0.0')\n\n            plugin ('jmh', 'me.champeau.jmh').versionRef('jmhGradlePlugin')\n\n            // *** Libraries ***\n\n            // https://mvnrepository.com/artifact/com.google.auto.service\n            library ('autoService', 'com.google.auto.service', 'auto-service').version('1.1.1')\n            // https://mvnrepository.com/artifact/org.jctools\n            library ('jctools', 'org.jctools', 'jctools-core').version('4.0.6')\n\n\n            // https://mvnrepository.com/artifact/org.slf4j\n            library ('slf4j',  'org.slf4j', 'slf4j-api').versionRef('slf4j')\n            library ('slf4j-simple',  'org.slf4j', 'slf4j-simple').versionRef('slf4j')\n\n            // https://mvnrepository.com/artifact/org.ow2.asm\n            library ('asm',  'org.ow2.asm', 'asm').versionRef('asm')\n            library ('asm-tree',  'org.ow2.asm', 'asm-tree').versionRef('asm')\n            library ('asm-util',  'org.ow2.asm', 'asm-util').versionRef('asm')\n\n            // https://mvnrepository.com/artifact/org.openjdk.jmh\n            library ('jmh', 'org.openjdk.jmh', 'jmh-core').versionRef('jmh')\n            library ('jmh-annprocess', 'org.openjdk.jmh', 'jmh-generator-annprocess').versionRef('jmh')\n\n            // https://mvnrepository.com/artifact/org.junit.jupiter\n            library ('junit', 'org.junit', 'junit-bom').versionRef('junit')\n            library ('junit-jupiter', 'org.junit.jupiter', 'junit-jupiter').versionRef('junit')\n            library ('testcontainers', 'org.testcontainers', 'testcontainers').versionRef('testcontainers')\n            library ('testcontainers-junit-jupiter', 'org.testcontainers', 'junit-jupiter').versionRef('testcontainers')\n\n            // https://mvnrepository.com/artifact/org.hdrhistogram/HdrHistogram\n            library ('hdrhistogram', 'org.hdrhistogram', 'HdrHistogram').version('2.2.2')\n\n            // https://mvnrepository.com/artifact/com.clearspring.analytics/stream\n            library ('stream-lib', 'com.clearspring.analytics', 'stream').version('2.9.8')\n        }\n    }\n}\n"
  }
]