Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Jvm Bytecode

ASecurity

Reading and reasoning about JVM bytecode: javap -c -p -v, operand stack and local slots, the constant pool and resolution timing, descriptors versus Signature, the invoke* family with invokedynamic and inline caching, verification and the StackMapTable, the class-file limits, what javac desugars, and what bytecode does and does not say about performance. Use when a VerifyError appears after instrumentation by an agent, proxy or mock library, when UnsupportedClassVersionError names two class f...

2 stars
0 votes
0 copies
0 views
Added 9/19/2026
developmentrustgojavaexpressapiperformance

Works with

api

Security Analysis

A100/100

Scanned 9/19/2026

Install to Claude Code

$npx -y skills add robsonkades/agent-skills --skill jvm-bytecode --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Jvm Bytecode?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Jvm Bytecode
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/robsonkades-jvm-bytecode/badge)](https://www.skillsdirectory.com/skills/robsonkades-jvm-bytecode)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: jvm-bytecode
description: >
  Reading and reasoning about JVM bytecode: javap -c -p -v, operand stack and local slots, the
  constant pool and resolution timing, descriptors versus Signature, the invoke* family with
  invokedynamic and inline caching, verification and the StackMapTable, the class-file limits,
  what javac desugars, and what bytecode does and does not say about performance. Use when a
  VerifyError appears after instrumentation by an agent, proxy or mock library, when
  UnsupportedClassVersionError names two class file versions, when javac reports "code too
  large", when a coverage or mocking agent fails with "Unsupported class file major version"
  after a JDK upgrade, when auditing what a lambda, record, sealed switch or synchronized block
  compiled to, when checking for hidden boxing in a hot method, or when a cycles-per-bytecode
  table is quoted. Does not cover tiered compilation or warm-up (jit-compilation),
  what the JIT did with the code (compilation-and-inlining-logs), or loading, linking and
  initialisation (jvm-class-loading).
---

# JVM Bytecode

## Purpose

Read what was actually compiled, rather than what the source appears to say. The failures
this skill prevents are the ones that only bytecode can settle: an intermittent `VerifyError`
from instrumentation whose final instructions and stack maps disagree, a coverage
agent that silently instruments nothing after a JDK upgrade, a build that stops on
`code too large`, and a performance argument built on the _shape_ of source code when the
shape that runs is different — string concatenation that is now `invokedynamic`, a `switch`
that is a `SwitchBootstraps` type switch, a one-line try-with-resources that is 38 bytes of
bytecode, boxing that nobody wrote.

Bytecode is a typed stack machine plus symbolic constant-pool references. Most instructions
carry indices rather than embedded names. The JVMS permits lazy or eager resolution while
constraining when failures become observable; dynamically computed constants/call sites have
their own lazy bootstrap rules. Loading, verification, resolution and initialization are
distinct—inspect the failure phase rather than assuming “first execution” universally.

## Workflow

1. **Preserve and inspect the actual artifact first.** Record its digest, selected JAR entry,
   loader/module, compiler release/options and target vendor/build. Recompile only for a separate
   reproduction; use `-g -parameters` when useful without overwriting the incident artifact.
   Examples here use JDK 25; Class-File API needs JDK 24+, not an implicit project upgrade. `javap`
   for signatures, `javap -c` for the code, `javap -c -p` to include private members,
   `javap -v` for the constant pool, the attributes and the `StackMapTable` (`-v` does not
   imply `-p`).
2. **Read the header before the instructions.** `major_version`, the access flags and
   `this_class` answer most version questions on their own — see
   `references/javap-and-class-file-anatomy.md`.
3. **Classify a `LinkageError` by its message before forming a hypothesis.** `VerifyError`,
   `ClassFormatError`, `UnsupportedClassVersionError` and a late `NoSuchMethodError` identify
   different failure categories; locate the actual producer separately. JDK 25 texts are in
   `references/limits-and-failure-catalogue.md`.
4. **Establish locals and stack state before tracing opcodes.** Derive parameter slots from
   the descriptor/access flags; `LocalVariableTable` is optional debug metadata with scoped
   names and reused slots. Slot 0 is `this` in an instance method; category-2 `long`/`double`
   values occupy two local slots.
5. **Classify every call site by instruction and symbolic reference.** Static/special calls
   have different resolution/selection rules from receiver-dispatched virtual/interface
   calls; javac 11+ may encode private nestmate calls with virtual/interface opcodes.
   `invokedynamic` links a call site through a bootstrap. Bytecode form is not the final
   dispatch cost after JIT compilation. See
   `references/dispatch-and-abstraction-cost.md`.
6. **Separate what bytecode can and cannot answer.** It shows interpreter-level instruction
   semantics, symbolic allocations/calls, and the code size consumed by JIT policy. It does
   not show what the JIT inlined, which
   speculation held, or how long anything took — hand those to
   `compilation-and-inlining-logs` and `jit-compilation`.
7. **For runtime-generated bytecode, dump it and disassemble the dump** — the generated class
   is the one the verifier rejected, not the original source. On JDK 25 the lambda dump is
   `-Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles=true`; the older property is silent.
8. **Match evidence to the cost claim.** Reuse applicable measurements with their workload,
   hardware, JDK and flags. A bytecode or API explanation can finish without a new benchmark;
   a quantitative runtime claim needs supporting evidence. If that evidence is missing, state
   the limit and propose the smallest discriminating check rather than inventing a cost.

## Rules

- Prefer `javap` or the Class-File API over a decompiler for exact dispatch/attribute
  questions. Decompilers reconstruct a readable approximation and re-sugar details that
  matter—implicit boxing and the real dispatch form.
- Never assume the same source produces the same bytecode across JDK versions. String
  concatenation has been `invokedynamic` since JDK 9 (JEP 280), private calls have been
  `invokevirtual` since JDK 11 (JEP 181), pattern `switch` uses `SwitchBootstraps` since
  JDK 21. These are javac lowering choices for the selected target, not guarantees about every
  compiler or class file. Explicit builders, constant-folded concatenation and `--release 8`
  output differ. Inspect control flow around concat call sites rather than using a keyword alone.
- Treat javac primarily as a lowering compiler, with limited folding/simplification whose
  exact output can change. A measured one-line try-with-resources example was 38 bytecode
  bytes—above one tested cold-site inline threshold but still eligible under other hot/policy
  paths. The 8,000-byte huge-method cutoff applies only with the corresponding HotSpot policy
  and has version/tier exceptions. The 64 KB class-file limit that stops the build is a
  different number from the 8,000-byte HotSpot policy cutoff—see the desugaring table in
  `references/dispatch-and-abstraction-cost.md`.
- For modern feature releases, `major_version = JDK version + 44`; JDK 25 is 69. An
  individual newer-version class file is rejected by an older runtime. Check both numbers,
  multi-release JAR selection, build image and runtime image—a `--release 25` build
  deployed onto a `21-jre` image surfaces as "the application will not start".
- A transformer must emit code, exception ranges, maximums and stack maps consistent with the
  final body. Recompute frames (ASM `COMPUTE_FRAMES`, or Class-File API generation) unless the
  transformation framework correctly remaps/preserves them. An absent physical
  `StackMapTable` on version 50+ means an implicit zero-entry table; branches that require
  frames still fail. Frame computation can load classes, so use a loader-aware hierarchy
  resolver and test circularity/module boundaries.
- A bytecode library's version is coupled to class-file versions and is often shaded
  inside something else. `Unsupported class file major version 69` from
  `org.objectweb.asm.ClassReader` means the agent, coverage tool or mocking library bundles
  an ASM that cannot parse the rejected class's version; identify its source and upgrade the
  tool or produce a compatible target artifact as appropriate. A `ClassFileTransformer` that throws is
  treated like returning `null`: later transformers and class definition still proceed. The
  class may load uninstrumented and the process may succeed, so gate instrumentation/coverage
  assertions explicitly rather than trusting exit code.
- Test instrumentation against the **same** JDK major version that runs in production, not
  only the development one. Include multi-release JAR entries, supported loaders/modules,
  retransformation and generated classes in the compatibility matrix. Hidden classes have
  instrumentation restrictions; do not promise that a normal transformer can observe or
  retransform lambda proxy definitions.
- Treat a Java agent or transformer as privileged production code: pin and verify its artifact,
  minimize its class/method scope, protect dumped bytecode because it may contain secrets, and
  make mandatory instrumentation fail an explicit readiness/deployment gate.
- Never disable verification to make a `VerifyError` go away. `-Xverify:none` and `-noverify`
  have warned since JDK 13 (JDK-8214719) and `BytecodeVerificationRemote` is a diagnostic
  flag on 25; disabling verification removes a structural/type safety gate and can turn
  rejection into unsafe execution or a later failure. `-XX:-UseSplitVerifier` is not ignored — it is
  `Unrecognized VM option` and the JVM does not start (removed in JDK 8, JDK-8009595).
- `invokedynamic` is not inherently slow. Resolution invokes a bootstrap and installs a linked
  call site; concurrent resolution and bootstrap failure rules are subtler than “runs exactly
  once”. Steady-state cost depends on the resulting target's mutability and JIT visibility.
- Lambda proxy classes have been **hidden classes** since JDK 15 (JEP 371), defined through
  `MethodHandles.Lookup::defineHiddenClass` rather than `Unsafe::defineAnonymousClass`. They
  are not discoverable by name — not via `Class.forName`, not via `getDeclaredClasses` — and
  the `$$Lambda/0x…` suffix is a runtime identity, not a stable sequential index.
- Non-capturing lambdas _tend_ to be a single reused instance and capturing ones _tend_ to
  allocate per invocation. That is `LambdaMetafactory` behaviour, not a JVMS guarantee.
  For an allocation claim, use suitable measurements in the actual escape context; JMH
  `-prof gc` is one option. Never assert allocation or instance identity from source shape.
- A `synchronized` block uses `monitorenter`/`monitorexit` with exceptional cleanup; the exact
  number/ranges of exception-table entries are javac/version/control-flow dependent. A synchronized
  method uses `ACC_SYNCHRONIZED` without explicit monitor instructions. Both have monitor
  semantics when locking the same object, but a method locks `this` (instance) or its declaring
  `Class` (static), while a block locks its evaluated expression and can cover a smaller region.
- The tested exhaustive pattern `switch` over a sealed type carries a synthetic `default` that
  throws `MatchException`. It can signal binary evolution at that default, but a record-pattern
  accessor throwing can also be wrapped in `MatchException`. Inspect location and cause before
  attributing it to stale artifacts.
- Treat receiver diversity as a property of a runtime call site, not the language. If it is
  materially hot, compare accepting dispatch, isolating a stable hot site or redesigning the
  abstraction; do not add type switches merely to game one JIT profile.
- Never generalize a cycles-per-bytecode-instruction table into a runtime cost. Post-JIT
  cost depends on microarchitecture, compilation tier, the inline cache state at that specific
  call site and memory layout. Preserve the conditions and limits of any measured number or
  cost model; an instruction count is not an elapsed-time measurement.
- Use `jmh-microbenchmarks` when designing or auditing an isolated instruction- or
  abstraction-cost experiment. A hand-timed loop alone does not control warm-up, elimination
  or shared JVM history. Choose timing/allocation instrumentation for the declared question;
  reuse adequate artifacts instead of requiring a fresh JMH or profiler run for every explanation.
- `obj instanceof String s` and `instanceof` followed by a cast compile to the **same**
  `instanceof`/`checkcast` pair on javac 25. Prefer the pattern for its scoping, not for a
  saved instruction that does not exist.
- A class file with `minor_version = 0xFFFF` depends on preview features and loads only on
  exactly that feature release, with `--enable-preview` at runtime as well as at compile time.
  Depending on a preview **API** is enough to set it; passing `--enable-preview` to a class
  that uses nothing preview is not.
- Verify any suspicious VM flag with `java -XX:+PrintFlagsFinal -version | grep -i <term>`
  before it goes into a runbook; a `develop` flag such as `HugeMethodLimit` is absent from that
  list on a product build and refuses to start the JVM.

## References

- [javap and class file anatomy](references/javap-and-class-file-anatomy.md) — the `javap`
  invocations, an annotated JDK 25 disassembly, `LocalVariableTable` versus
  `MethodParameters`, the `major_version` table and the preview marker, the constant pool
  entry kinds including `MethodHandle`/`MethodType`/`Dynamic`, descriptors versus `Signature`,
  what the verifier checks with the exact `VerifyError` texts, the JDK 25 lambda dump property,
  and the Class-File API next to ASM. Read when disassembling anything, when diagnosing a
  `VerifyError`, or when writing or fixing a class transformer.
- [Dispatch and abstraction cost](references/dispatch-and-abstraction-cost.md) — the invoke
  family, tier-specific dispatch/profile behavior, the table of what javac lowers each construct
  to and how large it gets (`synchronized`, `finally`, try-with-resources, the three `switch`
  shapes, records, `assert`, boxing), lambdas and hidden classes, the abstraction comparison
  table, and grep recipes that work on modern class files. Read when the question is what a
  call site costs, which abstraction to choose, or why a small method was not inlined.
- [Limits and the failure catalogue](references/limits-and-failure-catalogue.md) — the
  symptom-to-cause table with JDK 25 message texts for `VerifyError`, `ClassFormatError`,
  `UnsupportedClassVersionError`, `code too large`, late `NoSuchMethodError`, and ASM,
  Byte Buddy and JaCoCo breakage after a JDK upgrade; the JVMS limits; the verification flags
  and why not to touch them. Read when a `LinkageError` or a javac limit error arrives, or
  when a hot method never appears in `PrintCompilation`.

Attribution

robsonkadesrobsonkades
View sourceMore from robsonkades →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →