Lesson 13-Bun.js Core Functionality Source Code Analysis

Module System Source Code

ESM Module Loading Process

ESM Loading Core Process:

// Pseudo-code showing the ESM module loading process
class ModuleLoader {
public:
    JSValueRef loadESMModule(const std::string& specifier, JSValueRef referrer) {
        // 1. Resolve module path
        std::string resolvedPath = resolveESMSpecifier(specifier, referrer);

        // 2. Check cache
        if (moduleCache.has(resolvedPath)) {
            return moduleCache.get(resolvedPath);
        }

        // 3. Create module record
        ModuleRecord* record = createModuleRecord(resolvedPath);

        // 4. Parse module dependency graph
        parseModuleDependencies(record);

        // 5. Compile to bytecode
        compileModule(record);

        // 6. Execute module
        JSValueRef namespace = executeModule(record);

        // 7. Cache module
        moduleCache.set(resolvedPath, namespace);

        return namespace;
    }

private:
    std::string resolveESMSpecifier(const std::string& specifier, JSValueRef referrer) {
        // Implement ESM specification resolution algorithm
        // Handle relative paths, absolute paths, package.json exports, etc.
    }
};

Key Optimization Points:

  1. Parallel Parsing: Use multi-threading for pre-parsing dependency graphs
  2. Caching Strategy: Module caching based on content hash
  3. Deferred Compilation: Compile unexecuted module branches on demand

CommonJS Compatibility Implementation

CommonJS Loader Core Logic:

class CommonJSLoader {
public:
    JSValueRef loadCJSModule(const std::string& filePath) {
        // 1. Check cache
        if (cjsCache.has(filePath)) {
            return cjsCache.get(filePath);
        }

        // 2. Create module object
        JSObjectRef moduleObj = JSObjectMake(context, moduleClass, nullptr);
        JSObjectRef exportsObj = JSObjectMake(context, nullptr, nullptr);
        JSObjectSetProperty(context, moduleObj, JSStringCreateWithUTF8CString("exports"), exportsObj, kJSPropertyAttributeNone, nullptr);

        // 3. Execute module code
        std::string sourceCode = readFile(filePath);
        JSValueRef result = evaluateScript(sourceCode, moduleObj);

        // 4. Handle exports
        if (JSValueIsObject(context, result)) {
            // Override exports if module returns an object
            JSObjectSetProperty(context, moduleObj, JSStringCreateWithUTF8CString("exports"), result, kJSPropertyAttributeNone, nullptr);
        }

        // 5. Cache module
        JSValueRef exports = JSObjectGetProperty(context, moduleObj, JSStringCreateWithUTF8CString("exports"), nullptr);
        cjsCache.set(filePath, exports);

        return exports;
    }
};

Compatibility Handling:

  1. require() Rewriting: Intercept require calls to enable hybrid loading
  2. __dirname/__filename: Dynamically compute to mimic Node.js behavior
  3. Circular Dependencies: Reference-based deferred resolution mechanism

Module Caching Implementation

Multi-level Cache Architecture:

class ModuleCache {
private:
    // In-memory cache (primary cache)
    std::unordered_map<std::string, JSValueRef> memoryCache;

    // Disk cache (secondary cache)
    DiskCache diskCache;

public:
    JSValueRef get(const std::string& key) {
        // 1. Check memory cache
        if (auto it = memoryCache.find(key); it != memoryCache.end()) {
            return it->second;
        }

        // 2. Check disk cache
        if (auto cached = diskCache.get(key)) {
            JSValueRef value = deserialize(*cached);
            memoryCache[key] = value; // Backfill memory cache
            return value;
        }

        return nullptr;
    }

    void set(const std::string& key, JSValueRef value) {
        // 1. Update memory cache
        memoryCache[key] = value;

        // 2. Asynchronously update disk cache
        diskCache.setAsync(key, serialize(value));
    }
};

Cache Invalidation Strategy:

  1. Content Hash: Generate cache keys based on file content
  2. Version Tags: Automatically invalidate on package.json version changes
  3. Manual Clearing: Support cache refresh in development mode

Dynamic Import Implementation

Dynamic import() Source Code Process:

class DynamicImporter {
public:
    JSValueRef importModule(const std::string& specifier) {
        // 1. Create new Promise object
        JSObjectRef promise = JSObjectMakePromise(context);

        // 2. Parse module in background thread
        threadPool.submit([this, specifier, promise]() {
            try {
                // 3. Actually load module (potentially across file systems)
                JSValueRef module = loadESMModule(specifier, nullptr);

                // 4. Resolve in event loop after completion
                eventLoop.post([promise, module]() {
                    JSObjectCallAsFunction(context, JSObjectGetPromiseResolve(context), nullptr, 1, &module, nullptr);
                });
            } catch (const std::exception& e) {
                // Error handling
                eventLoop.post([promise, e]() {
                    JSValueRef error = createErrorFromException(e);
                    JSObjectCallAsFunction(context, JSObjectGetPromiseReject(context), nullptr, 1, &error, nullptr);
                });
            }
        });

        return promise;
    }
};

Key Features:

  1. Lazy Loading: Module code loaded only on import() call
  2. Topological Sorting: Maintain topological relationships for dynamic dependencies
  3. Cache Isolation: Independent caching for dynamically imported modules

Module Resolution Mechanism

Complete Resolution Algorithm Implementation:

class ModuleResolver {
public:
    std::string resolve(const std::string& specifier, const std::string& referrer) {
        // 1. Check if absolute or relative path
        if (isAbsolutePath(specifier)) {
            return normalizePath(specifier);
        }

        if (isRelativePath(specifier)) {
            return resolveRelativePath(specifier, referrer);
        }

        // 2. Handle package names (follow package.json exports)
        if (isPackageName(specifier)) {
            return resolvePackageName(specifier, referrer);
        }

        // 3. Other cases (e.g., Node built-in modules)
        return resolveBuiltinModule(specifier);
    }

private:
    std::string resolvePackageName(const std::string& packageName, const std::string& referrer) {
        // 1. Find nearest node_modules
        std::string basePath = findNearestNodeModules(referrer);

        // 2. Check package.json exports field
        PackageMeta meta = readPackageMeta(basePath, packageName);

        // 3. Resolve final path based on exports rules
        return applyExportsRules(meta, specifier);
    }
};

Special Handling:

  1. package.json exports: Support conditional exports and subpath mapping
  2. Extension Inference: Try .js/.mjs/.json extensions in order
  3. Main Field Selection: Based on package.json main/module/browser fields

Event Loop and Asynchronous I/O Source Code

Event Loop Implementation

Event Loop Core Structure:

class EventLoop {
private:
    // I/O event multiplexer
#ifdef __linux__
    int epfd; // epoll file descriptor
#elif __APPLE__
    int kq;   // kqueue file descriptor
#endif

    // Timer heap
    std::priority_queue<TimerEvent> timerQueue;

    // Immediate execution queue
    std::queue<ImmediateTask> immediateQueue;

public:
    void run() {
        while (!shouldExit) {
            // 1. Calculate next timer expiration
            int timeout = calculateNextTimeout();

            // 2. Wait for I/O events
            waitIOEvents(timeout);

            // 3. Process ready I/O events
            processReadyIO();

            // 4. Execute expired timers
            executeExpiredTimers();

            // 5. Execute immediate tasks
            executeImmediateTasks();
        }
    }
};

Key Optimizations:

  1. Multi-Platform Adaptation: Unified interface for epoll/kqueue/IOCP
  2. Batch Processing: Merge system calls to reduce context switching
  3. Priority Scheduling: Differentiate priorities for I/O and timer tasks

Asynchronous I/O Operations

File Read Asynchronous Implementation:

class AsyncFileReader {
public:
    void readFile(const std::string& path, Callback callback) {
        // 1. Submit to thread pool for blocking I/O
        threadPool.submit([this, path, callback]() {
            std::string content = syncReadFile(path);

            // 2. Post result back to event loop thread
            eventLoop.post([callback, content]() {
                callback(content);
            });
        });
    }
};

Network Request Asynchronous Implementation:

class AsyncHTTPClient {
public:
    void get(const std::string& url, Callback callback) {
        // 1. Parse URL to get host and port
        URLInfo info = parseURL(url);

        // 2. Create non-blocking socket
        int sockfd = createNonBlockingSocket();

        // 3. Asynchronous DNS resolution
        dnsResolver.resolve(info.host, [this, sockfd, info, callback](std::vector<IPAddress> addresses) {
            // 4. Asynchronous connection
            asyncConnect(sockfd, addresses, [this, sockfd, info, callback]() {
                // 5. Asynchronous request sending
                asyncSendRequest(sockfd, info, [this, sockfd, callback]() {
                    // 6. Asynchronous response receiving
                    asyncReceiveResponse(sockfd, callback);
                });
            });
        });
    }
};

Timer Implementation

Timer Management Core Logic:

class TimerManager {
private:
    std::priority_queue<TimerEvent> timerQueue;
    std::mutex queueMutex;

public:
    int setTimeout(Callback callback, uint64_t delayMs) {
        TimerEvent event{
            .id = generateTimerId(),
            .callback = callback,
            .expireTime = getCurrentTime() + delayMs
        };

        {
            std::lock_guard<std::mutex> lock(queueMutex);
            timerQueue.push(event);
        }

        return event.id;
    }

    void processTimers() {
        uint64_t now = getCurrentTime();
        std::vector<TimerEvent> expiredEvents;

        {
            std::lock_guard<std::mutex> lock(queueMutex);
            while (!timerQueue.empty() && timerQueue.top().expireTime <= now) {
                expiredEvents.push_back(timerQueue.top());
                timerQueue.pop();
            }
        }

        for (auto& event : expiredEvents) {
            event.callback();
        }
    }
};

Optimization Strategies:

  1. Time Wheel Algorithm: Efficiently manage large numbers of timers
  2. Batch Processing: Merge timer callbacks with similar timing
  3. Lazy Deletion: Mark timers for deletion instead of immediate removal

Concurrency Control Implementation

Promise.all Source Code Implementation:

class PromiseAll {
public:
    static JSValueRef all(JSContextRef ctx, size_t argc, const JSValueRef argv[]) {
        // 1. Create result array and completion counter
        JSObjectRef resultArray = JSObjectMakeArray(ctx, 0, nullptr, nullptr);
        std::atomic<size_t> completedCount = 0;
        size_t totalPromises = argc;

        // 2. Create new Promise as return value
        JSObjectRef promise = JSObjectMakePromise(ctx);

        // 3. Add callbacks for each Promise
        for (size_t i = 0; i < totalPromises; i++) {
            JSValueRef promise = argv[i];
            size_t index = i; // Capture current index

            JSObjectCallAsFunction(ctx, JSObjectGetPromiseThen(ctx, promise), nullptr, 2,
                (JSValueRef[]){
                    createCallback(ctx, [ctx, resultArray, index, &completedCount, totalPromises, promise](JSValueRef value) {
                        // Success callback
                        JSObjectSetPropertyAtIndex(ctx, resultArray, index, value, nullptr);
                        if (++completedCount == totalPromises) {
                            JSObjectCallAsFunction(ctx, JSObjectGetPromiseResolve(ctx, promise), nullptr, 1, &resultArray, nullptr);
                        }
                    }),
                    createCallback(ctx, [ctx, promise](JSValueRef reason) {
                        // Failure callback
                        JSObjectCallAsFunction(ctx, JSObjectGetPromiseReject(ctx, promise), nullptr, 1, &reason, nullptr);
                    })
                }, nullptr);
        }

        return promise;
    }
};

Concurrency Strategies:

  1. Promise.all: Resolves when all succeed or rejects on first failure
  2. Promise.race: Resolves/rejects on first completion
  3. Promise.allSettled: Waits for all to complete

Exception Handling Implementation

Asynchronous Exception Propagation Mechanism:

class AsyncExceptionHandler {
public:
    void handleUncaughtException(JSContextRef ctx, JSValueRef exception) {
        // 1. Get exception stack trace
        std::string stackTrace = getStackTrace(ctx, exception);

        // 2. Format error message
        std::string errorMessage = formatErrorMessage(ctx, exception, stackTrace);

        // 3. Output to error stream
        std::cerr << errorMessage << std::endl;

        // 4. Trigger global error event
        emitGlobalErrorEvent(ctx, exception);
    }

    void wrapAsyncCallback(Callback original, JSContextRef ctx) {
        return [original, ctx](auto&&... args) {
            try {
                original(std::forward<decltype(args)>(args)...);
            } catch (const std::exception& e) {
                JSValueRef exception = createErrorFromException(e);
                handleUncaughtException(ctx, exception);
            }
        };
    }
};

Key Mechanisms:

  1. Exception Capture Boundary: Each async operation has corresponding exception handling
  2. Stack Tracing: Call chain tracking across async calls
  3. Global Error Handling: Simulate unhandledrejection event

Built-in Toolchain Source Code

Package Manager Implementation

Dependency Resolution Algorithm:

class DependencyResolver {
public:
    ResolutionResult resolve(const PackageGraph& graph) {
        // 1. Topological sort to detect circular dependencies
        if (hasCycle(graph)) {
            throw CycleDependencyError();
        }

        // 2. Version selection (semantic version parsing)
        VersionSelectionResult selection = selectVersions(graph);

        // 3. Generate installation plan
        InstallationPlan plan = generateInstallationPlan(selection);

        return plan;
    }

private:
    bool hasCycle(const PackageGraph& graph) {
        // Use Kahn's algorithm or DFS to detect cycles
    }
};

Key Installation Process Steps:

  1. Package Download: Support multiple protocols (tarball/git)
  2. Extraction and Verification: Validate file integrity (SHA-256)
  3. Link Installation: Hard links to optimize disk space
  4. Metadata Generation: Record installed versions and dependencies

Test Framework Implementation

Test Runner Core Logic:

class TestRunner {
public:
    void runTests(const std::vector<TestCase>& tests) {
        // 1. Initialize test environment
        setupTestEnvironment();

        // 2. Execute test cases
        for (const auto& test : tests) {
            runSingleTest(test);
        }

        // 3. Generate report
        generateReport();
    }

    void runSingleTest(const TestCase& test) {
        // 1. Start timing
        auto start = std::chrono::high_resolution_clock::now();

        // 2. Execute test
        TestResult result;
        try {
            test.fn();
            result.status = TestStatus::Passed;
        } catch (const AssertionFailure& e) {
            result.status = TestStatus::Failed;
            result.message = e.what();
        } catch (...) {
            result.status = TestStatus::Errored;
        }

        // 3. Record result
        result.duration = std::chrono::high_resolution_clock::now() - start;
        testResults.push_back(result);
    }
};

Assertion System Implementation:

class AssertionSystem {
public:
    void equal(const T& a, const T& b, const std::string& message) {
        if (a != b) {
            throw AssertionFailure(message + 
                "\nExpected: " + toString(a) + 
                "\nActual: " + toString(b));
        }
    }

    // Other assertion methods...
};

Bundler Implementation

Key Bundling Process Stages:

class Bundler {
public:
    void bundle(const std::string& entry) {
        // 1. Parse dependency graph
        DependencyGraph graph = buildDependencyGraph(entry);

        // 2. Transform code
        transformCode(graph);

        // 3. Generate optimized code
        generateOutput(graph);
    }

    void transformCode(DependencyGraph& graph) {
        // 1. Apply Babel plugins to transform syntax
        applyBabelTransforms(graph);

        // 2. Tree-shaking to remove unused code
        performTreeShaking(graph);

        // 3. Scope hoisting
        hoistScopes(graph);
    }
};

Optimization Strategies:

  1. Scope Hoisting: Merge module scopes
  2. Tree Shaking: Static analysis to remove dead code
  3. Code Splitting: Support for dynamic imports

Script Executor Implementation

bun run Command Implementation:

class ScriptRunner {
public:
    void run(const std::string& scriptName) {
        // 1. Find script definition
        ScriptDefinition def = findScriptDefinition(scriptName);

        // 2. Prepare environment variables
        Environment env = prepareEnvironment(def);

        // 3. Execute command
        executeCommand(def.command, env);
    }

    void executeCommand(const std::string& command, const Environment& env) {
        // 1. Parse command and arguments
        ParsedCommand parsed = parseCommand(command);

        // 2. Create child process
        Process process = createProcess(parsed.command, parsed.args, env);

        // 3. Manage process lifecycle
        manageProcess(process);
    }
};

Feature Support:

  1. Environment Variable Inheritance: Smart environment variable management
  2. Signal Handling: Properly handle SIGINT and other signals
  3. Concurrency Control: Parallel execution of multiple scripts

REPL Implementation

REPL Core Loop:

class REPL {
public:
    void run() {
        while (true) {
            // 1. Display prompt
            displayPrompt();

            // 2. Read user input
            std::string input = readInput();

            // 3. Parse input
            ParseResult result = parseInput(input);

            // 4. Execute code
            if (result.type == ParseResult::Command) {
                handleCommand(result);
            } else {
                executeCode(result.code);
            }

            // 5. Display result
            displayResult(lastEvaluationResult);
        }
    }

    void executeCode(const std::string& code) {
        // 1. Create temporary module context
        JSValueRef module = createTemporaryModule();

        // 2. Execute code
        JSValueRef result = evaluateInContext(code, module);

        // 3. Save result for next use
        lastEvaluationResult = result;
    }
};

Advanced Features:

  1. Multi-line Input: Smart indentation detection
  2. History Support: Up/down arrow browsing
  3. Magic Commands: Built-in special commands (e.g., .help)

Share your love