

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
1# V8 C++ API Implementation Guide23This directory contains Bun's implementation of the V8 C++ API on top of JavaScriptCore. This allows native Node.js modules that use V8 APIs to work with Bun.45## Architecture Overview67Bun implements V8 APIs by creating a compatibility layer that:89- Maps V8's `Local<T>` handles to JSC's `JSValue` system10- Uses handle scopes to manage memory lifetimes similar to V811- Provides V8-compatible object layouts that inline V8 functions can read12- Manages tagged pointers for efficient value representation1314For detailed background, see the blog series:1516- [Part 1: Introduction and challenges](https://bun.com/blog/how-bun-supports-v8-apis-without-using-v8-part-1.md)17- [Part 2: Memory layout and object representation](https://bun.com/blog/how-bun-supports-v8-apis-without-using-v8-part-2.md)18- [Part 3: Garbage collection and primitives](https://bun.com/blog/how-bun-supports-v8-apis-without-using-v8-part-3.md)1920## Directory Structure2122```23src/jsc/bindings/v8/24├── v8.h # Main header with V8_UNIMPLEMENTED macro25├── v8_*.h # V8 compatibility headers26├── V8*.h # V8 class headers (Number, String, Object, etc.)27├── V8*.cpp # V8 class implementations28├── shim/ # Internal implementation details29│ ├── Handle.h # Handle and ObjectLayout implementation30│ ├── HandleScopeBuffer.h # Handle scope memory management31│ ├── TaggedPointer.h # V8-style tagged pointer implementation32│ ├── Map.h # V8 Map objects for inline function compatibility33│ ├── GlobalInternals.h # V8 global state management34│ ├── InternalFieldObject.h # Objects with internal fields35│ └── Oddball.h # Primitive values (undefined, null, true, false)36├── node.h # Node.js module registration compatibility37└── real_v8.h # Includes real V8 headers when needed38```3940## Implementing New V8 APIs4142### 1. Create Header and Implementation Files4344Create `V8NewClass.h`:4546```cpp47#pragma once4849#include "v8.h"50#include "V8Local.h"51#include "V8Isolate.h"5253namespace v8 {5455class NewClass : public Data {56public:57 BUN_EXPORT static Local<NewClass> New(Isolate* isolate, /* parameters */);58 BUN_EXPORT /* return_type */ SomeMethod() const;5960 // Add other methods as needed61};6263} // namespace v864```6566Create `V8NewClass.cpp`:6768```cpp69#include "V8NewClass.h"70#include "V8HandleScope.h"71#include "v8_compatibility_assertions.h"7273ASSERT_V8_TYPE_LAYOUT_MATCHES(v8::NewClass)7475namespace v8 {7677Local<NewClass> NewClass::New(Isolate* isolate, /* parameters */)78{79 // Implementation - typically:80 // 1. Create JSC value81 // 2. Get current handle scope82 // 3. Create local handle83 return isolate->currentHandleScope()->createLocal<NewClass>(isolate->vm(), /* JSC value */);84}8586/* return_type */ NewClass::SomeMethod() const87{88 // Implementation - typically:89 // 1. Convert this Local to JSValue via localToJSValue()90 // 2. Perform JSC operations91 // 3. Return converted result92 auto jsValue = localToJSValue();93 // ... JSC operations ...94 return /* result */;95}9697} // namespace v898```99100### 2. Add Symbol Exports101102For each new C++ method, you must add the mangled symbol names to multiple files:103104#### a. Add to `src/runtime/napi/napi_body.rs`105106Find the `v8_api` module and add entries to both the `#[cfg(not(windows))]` (Itanium) and `#[cfg(windows)]` (MSVC) `extern "C"` blocks:107108```rust109#[cfg(not(windows))]110mod v8_api {111 use core::ffi::c_void;112 unsafe extern "C" {113 // ... existing functions ...114 pub(super) fn _ZN2v88NewClass3NewEPNS_7IsolateE/* parameters */() -> *mut c_void;115 pub(super) fn _ZNK2v88NewClass10SomeMethodEv() -> *mut c_void;116 }117}118#[cfg(windows)]119mod v8_api {120 use core::ffi::c_void;121 unsafe extern "C" {122 // ... existing functions ...123 #[link_name = "?New@NewClass@v8@@SA?AV?$Local@VNewClass@v8@@@2@PEAVIsolate@2@/* parameters */@Z"]124 pub(super) fn NewClass_New() -> *mut c_void;125 #[link_name = "?SomeMethod@NewClass@v8@@QEBA/* return_type */XZ"]126 pub(super) fn NewClass_SomeMethod() -> *mut c_void;127 }128}129```130131**To get the correct mangled names:**132133For **GCC/Clang** (Unix):134135```bash136# Build your changes first137bun bd --help # This compiles your code138139# Extract symbols140nm build/CMakeFiles/bun-debug.dir/src/jsc/bindings/v8/V8NewClass.cpp.o | grep "T _ZN2v8"141```142143For **MSVC** (Windows):144145```powershell146# Use the provided PowerShell script in the comments:147dumpbin .\build\CMakeFiles\bun-debug.dir\src\jsc\bindings\v8\V8NewClass.cpp.obj /symbols | where-object { $_.Contains(' v8::') } | foreach-object { (($_ -split "\|")[1] -split " ")[1] } | ForEach-Object { "#[link_name = `"${_}`"] pub(super) fn ___() -> *mut c_void;" }148```149150#### b. Add to Symbol Files151152Add to `src/symbols.txt` (without leading underscore):153154```155_ZN2v88NewClass3NewEPNS_7IsolateE...156_ZNK2v88NewClass10SomeMethodEv157```158159Add to `src/symbols.dyn` (with leading underscore and semicolons):160161```162{163 __ZN2v88NewClass3NewEPNS_7IsolateE...;164 __ZNK2v88NewClass10SomeMethodEv;165}166```167168**Note:** `src/symbols.def` is Windows-only and typically doesn't contain V8 symbols.169170### 3. Add Tests171172Create tests in `test/v8/v8-module/main.cpp`:173174```cpp175void test_new_class_feature(const FunctionCallbackInfo<Value> &info) {176 Isolate* isolate = info.GetIsolate();177178 // Test your new V8 API179 Local<NewClass> obj = NewClass::New(isolate, /* parameters */);180 auto result = obj->SomeMethod();181182 // Print results for comparison with Node.js183 std::cout << "Result: " << result << std::endl;184185 info.GetReturnValue().Set(Undefined(isolate));186}187```188189Add the test to the registration section:190191```cpp192void Init(Local<Object> exports, Local<Value> module, Local<Context> context) {193 // ... existing functions ...194 NODE_SET_METHOD(exports, "test_new_class_feature", test_new_class_feature);195}196```197198Add test case to `test/v8/v8.test.ts`:199200```typescript201describe("NewClass", () => {202 it("can use new feature", async () => {203 await checkSameOutput("test_new_class_feature", []);204 });205});206```207208### 4. Handle Special Cases209210#### Objects with Internal Fields211212If implementing objects that need internal fields, extend `InternalFieldObject`:213214```cpp215// In your .h file216class MyObject : public InternalFieldObject {217 // ... implementation218};219```220221#### Primitive Values222223For primitive values, ensure they work with the `Oddball` system in `shim/Oddball.h`.224225#### Template Classes226227For `ObjectTemplate` or `FunctionTemplate` implementations, see existing patterns in `V8ObjectTemplate.cpp` and `V8FunctionTemplate.cpp`.228229## Memory Management Guidelines230231### Handle Scopes232233- All V8 values must be created within an active handle scope234- Use `isolate->currentHandleScope()->createLocal<T>()` to create handles235- Handle scopes automatically clean up when destroyed236237### JSC Integration238239- Use `localToJSValue()` to convert V8 handles to JSC values240- Use `JSC::WriteBarrier` for heap-allocated references241- Implement `visitChildren()` for custom heap objects242243### Tagged Pointers244245- Small integers (±2^31) are stored directly as Smis246- Objects use pointer tagging with map pointers247- Doubles are stored in object layouts with special maps248249## Testing Strategy250251### Comprehensive Testing252253The V8 test suite compares output between Node.js and Bun for the same C++ code:2542551. **Install Phase**: Sets up identical module builds for Node.js and Bun2562. **Build Phase**: Compiles native modules using node-gyp2573. **Test Phase**: Runs identical C++ functions and compares output258259### Test Categories260261- **Primitives**: undefined, null, booleans, numbers, strings262- **Objects**: creation, property access, internal fields263- **Arrays**: creation, length, iteration, element access264- **Functions**: callbacks, templates, argument handling265- **Memory**: handle scopes, garbage collection, external data266- **Advanced**: templates, inheritance, error handling267268### Adding New Tests2692701. Add C++ test function to `test/v8/v8-module/main.cpp`2712. Register function in the module exports2723. Add test case to `test/v8/v8.test.ts` using `checkSameOutput()`2734. Run with: `bun bd test test/v8/v8.test.ts -t "your test name"`274275## Debugging Tips276277### Build and Test278279```bash280# Build debug version (takes ~5 minutes)281bun bd --help282283# Run V8 tests284bun bd test test/v8/v8.test.ts285286# Run specific test287bun bd test test/v8/v8.test.ts -t "can create small integer"288```289290### Common Issues291292**Symbol Not Found**: Ensure mangled names are correctly added to `napi_body.rs` and symbol files.293294**Segmentation Fault**: Usually indicates inline V8 functions are reading incorrect memory layouts. Check `Map` setup and `ObjectLayout` structure.295296**GC Issues**: Objects being freed prematurely. Ensure proper `WriteBarrier` usage and `visitChildren()` implementation.297298**Type Mismatches**: Use `v8_compatibility_assertions.h` macros to verify type layouts match V8 expectations.299300### Debug Logging301302Use `V8_UNIMPLEMENTED()` macro for functions not yet implemented:303304```cpp305void MyClass::NotYetImplemented() {306 V8_UNIMPLEMENTED();307}308```309310## Advanced Topics311312### Inline Function Compatibility313314Many V8 functions are inline and compiled into native modules. The memory layout must exactly match what these functions expect:315316- Objects start with tagged pointer to `Map`317- Maps have instance type at offset 12318- Handle scopes store tagged pointers319- Primitive values at fixed global offsets320321### Cross-Platform Considerations322323- Symbol mangling differs between GCC/Clang and MSVC324- Handle calling conventions (JSC uses System V on Unix)325- Ensure `BUN_EXPORT` visibility on all public functions326- Test on all target platforms via CI327328## Contributing329330When contributing V8 API implementations:3313321. **Follow existing patterns** in similar classes3332. **Add comprehensive tests** that compare with Node.js3343. **Update all symbol files** with correct mangled names3354. **Document any special behavior** or limitations336337For questions about V8 API implementation, refer to the blog series linked above or examine existing implementations in this directory.338
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| oven-sh/bunsrc/CLAUDE.md · 95k | CLAUDE.md | setupbuildlint-formatstyle+3 | 80/100 | 8 days ago | |
| oven-sh/bunCLAUDE.md · 95k | CLAUDE.md | buildteststylearch+3 | 96/100 | 14 days ago | |
| oven-sh/bunscripts/verify-baseline-static/CLAUDE.md · 95k | CLAUDE.md | buildtesting-strategy | 65/100 | 14 days ago | |
| oven-sh/bunsrc/js/CLAUDE.md · 95k | CLAUDE.md | buildarchdo-not | 85/100 | 14 days ago | |
| oven-sh/bunsrc/jsc/bindings/v8/AGENTS.md · 95k | AGENTS.md | buildtestarchtesting-strategy+4 | 81/100 | 14 days ago | |
| oven-sh/buntest/CLAUDE.md · 95k | CLAUDE.md | teststyletesting-strategydo-not | 97/100 | 14 days ago | |
| oven-sh/buntest/js/node/test/parallel/CLAUDE.md · 95k | CLAUDE.md | test | 43/100 | 14 days ago | |
| oven-sh/bun.github/workflows/CLAUDE.md · 95k | CLAUDE.md | setuptestlint-formatarch+4 | 86/100 | today |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| bagisto/bagistoCLAUDE.md · 28k | CLAUDE.md | setupbuildteststyle+5 | 100/100 | 7 days ago | |
| Adit-Jain-srm/NightmareNetCLAUDE.md · 46 | CLAUDE.md | buildtestlint-formatstyle+6 | 100/100 | 14 days ago | |
| tyrchen/geektime-bootcamp-aiw7/genslides/backend/CLAUDE.md · 230 | CLAUDE.md | testlint-formatstylearch+6 | 100/100 | 9 days ago | |
| nimbalyst/nimbalystpackages/android/CLAUDE.md · 1.5k | CLAUDE.md | setupbuildstylearch+2 | 100/100 | 14 days ago | |
| dotCMS/corecore-web/CLAUDE.md · 949 | CLAUDE.md | teststylearchtesting-strategy+3 | 100/100 | 14 days ago | |
| microsoft/playwrightCLAUDE.md · 95k | CLAUDE.md | buildtestlint-formatstyle+7 | 100/100 | 7 days ago | |
| tphakala/birdnet-goCLAUDE.md · 1.6k | CLAUDE.md | buildtestlint-formatstyle+8 | 100/100 | today | |
| livewire/livewireCLAUDE.md · 24k | CLAUDE.md | setupbuildteststyle+4 | 100/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/oven-sh-bun-src-jsc-bindings-v8-claude)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.