Skip to content

baishuijianjia/jsvmp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🚀 JSVMP - JavaScript Virtual Machine

npm version License: MIT

一个基于栈式架构的 JavaScript 虚拟机,支持在沙盒环境中安全执行 JavaScript 代码。使用 Babel AST 解析和字节码编译技术,提供完整的 JavaScript 语法支持。

✨ 特性

🎯 核心功能

  • 🔒 安全沙盒: 隔离执行环境,不影响宿主程序
  • 📚 完整语法支持: 变量、函数、对象、数组、循环、条件语句
  • 🔄 栈式架构: 基于操作数栈的高效字节码执行
  • 🌳 AST 解析: 基于成熟的 Babel 解析器
  • 🎛️ 调试友好: 支持多级调试和错误追踪

🚀 高级特性

  • ⚡ 函数调用: 递归、闭包、回调函数
  • 📦 作用域管理: 词法作用域和变量提升
  • 🏗️ 对象系统: 原型链、方法调用、构造函数
  • 📊 内置对象: console、Math、String、Array 等
  • 📥 外部变量: 安全传入外部数据、函数和API
  • 🔧 灵活配置: 执行限制、调试模式、性能监控
  • 🔍 调试系统: 完整的调试符号和源码追踪

📦 安装

npm install jsvmp

🚀 快速开始

基本使用

const { JSVMP } = require('jsvmp');

// 创建虚拟机实例
const vm = new JSVMP();

// 执行简单表达式
const result1 = vm.run('2 + 3 * 4'); // 14

// 执行函数定义和调用
const result2 = vm.run(`
    function add(a, b) {
        return a + b;
    }
    add(10, 20)
`); // 30

console.log(result1, result2);

外部变量传入

const { JSVMP } = require('jsvmp');

const vm = new JSVMP();

// 传入外部数据和函数
const result = vm.run(`
    // 使用外部传入的变量
    var message = "Hello, " + userName + "!";
    var doubled = multiply(score, 2);
    var userInfo = user.name + " (" + user.email + ")";
    
    ({
        message: message,
        doubled: doubled,
        userInfo: userInfo
    })
`, {
    // 外部变量 - 会成为虚拟机的全局变量
    userName: "张三",
    score: 85,
    user: { name: "李四", email: "lisi@example.com" },
    multiply: function(a, b) { return a * b; }
});

console.log(result);
// 输出: {
//   message: "Hello, 张三!",
//   doubled: 170,
//   userInfo: "李四 (lisi@example.com)"
// }

高级示例

const { JSVMP } = require('jsvmp');

const vm = new JSVMP();

// 复杂算法 - 斐波那契数列
const fibonacciCode = `
    function fibonacci(n) {
        if (n <= 1) return n;
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
    
    var result = [];
    for (var i = 0; i < 10; i++) {
        result.push(fibonacci(i));
    }
    result
`;

const fibonacci = vm.run(fibonacciCode);
console.log('斐波那契数列:', fibonacci);
// 输出: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

// 闭包隔离演示 - 多个计数器相互独立
const closureCode = `
    function createCounter(initialValue) {
        var count = initialValue || 0;
        
        return function() {
            count++;
            return count;
        };
    }

    var counter1 = createCounter(10);
    var counter2 = createCounter(100);

    var results = [];
    results.push(counter1()); // 11
    results.push(counter1()); // 12
    results.push(counter2()); // 101
    results.push(counter1()); // 13
    results.push(counter2()); // 102

    results
`;

const closureResult = vm.run(closureCode);
console.log('闭包隔离结果:', closureResult);
// 输出: [11, 12, 101, 13, 102]

浏览器使用

<!DOCTYPE html>
<html>
<head>
    <title>JSVMP Web 示例</title>
</head>
<body>
    <script src="dist/jsvmp.js"></script>
    <script>
        const vm = new JSVMP.JSVMP();
        
        // 基本使用
        const result = vm.run(`
            var greeting = "Hello, JSVMP!";
            var numbers = [1, 2, 3, 4, 5];
            var sum = 0;
            
            for (var i = 0; i < numbers.length; i++) {
                sum += numbers[i];
            }
            
            greeting + " Sum: " + sum
        `);
        
        console.log(result); // "Hello, JSVMP! Sum: 15"
        
        // 传入外部变量 (浏览器环境)
        const browserResult = vm.run(`
            var info = userName + " 访问于 " + currentTime;
            var elementExists = domHelper.checkElement("myButton");
            
            ({
                info: info,
                elementExists: elementExists
            })
        `, {
            userName: "用户123",
            currentTime: new Date().toLocaleString('zh-CN'),
            domHelper: {
                checkElement: (id) => !!document.getElementById(id)
            }
        });
        
        console.log(browserResult);
    </script>
</body>
</html>

📖 API 文档

JSVMP 类

构造函数

const vm = new JSVMP();

主要方法

run(code, context?)

编译并执行 JavaScript 代码

参数:

  • code (string): 要执行的JavaScript代码
  • context (object, 可选): 外部变量对象,所有属性会成为虚拟机的全局变量

返回值: 代码执行结果

// 基本执行
const result = vm.run('Math.max(1, 2, 3)'); // 3

// 传入外部变量
const result2 = vm.run('x + y + z', { x: 1, y: 2, z: 3 }); // 6

// 传入函数和对象
const result3 = vm.run(`
    var processed = processData(numbers);
    var info = user.name + " has " + processed.length + " items";
    info
`, {
    numbers: [1, 2, 3, 4, 5],
    user: { name: "Alice" },
    processData: function(arr) { return arr.filter(x => x > 2); }
});

// 支持的外部数据类型:
// - 基本类型: string, number, boolean, null, undefined
// - 对象: 普通对象、数组、日期等
// - 函数: 普通函数、类实例方法
// - 类实例: 完整的类对象
compile(code)

编译代码为字节码(不执行)

const bytecode = vm.compile(`
    function greet(name) {
        return "Hello, " + name + "!";
    }
`);
execute(bytecode, context?)

执行已编译的字节码

参数:

  • bytecode (object): 编译后的字节码对象
  • context (object, 可选): 外部变量对象
const bytecode = vm.compile('x * 2 + y');
const result = vm.execute(bytecode, { x: 10, y: 5 }); // 25

配置方法

enableDebug(level?) / disableDebug()

控制调试模式

vm.enableDebug('verbose'); // 详细调试信息
vm.enableDebug('detail');  // 详细调试信息  
vm.enableDebug('basic');   // 基本调试信息
vm.disableDebug();         // 关闭调试
setDebugSymbols(enable)

设置调试符号开关

vm.setDebugSymbols(true);  // 启用调试符号,提供源码位置信息
vm.setDebugSymbols(false); // 禁用调试符号,提高性能
setMaxInstructions(count)

设置最大指令执行数量(防止死循环)

vm.setMaxInstructions(100000); // 限制最多执行10万条指令
reset()

重置虚拟机状态

vm.reset(); // 清空所有变量和状态
getState()

获取当前虚拟机状态

const state = vm.getState();
console.log(state); 
// {
//   initialized: true,
//   globalVariables: ['myVar', 'myFunction'],
//   callStackDepth: 0
// }

🎯 支持的语法

✅ 已支持

基础语法

  • 字面量: 数字、字符串、布尔值、null、undefined
  • 变量: var 声明、赋值、作用域
  • 运算符: 算术(+,-,*,/,%)、逻辑(&&,||,!)、比较(<,>,==,!=)、位运算(&,|,^,<<,>>)
  • 表达式: 二元、一元、三元条件、序列表达式

控制流

  • 条件: if/else 语句、三元运算符
  • 循环: for、while、do-while、for-in 循环
  • 跳转: break、continue、return 语句

函数

  • 声明: function 声明和表达式
  • 调用: 普通调用、方法调用、递归调用
  • 高级: 闭包、回调函数、函数作为值传递

对象和数组

  • 对象: 字面量、属性访问、方法调用、构造函数
  • 数组: 字面量、索引访问、length 属性
  • this: 正确的 this 绑定和上下文

内置对象

  • console: log() 方法输出
  • Math: 完整的数学函数和常量 (PI, E, abs, max, min, sqrt, sin, cos, etc.)
  • 全局函数: parseInt, parseFloat, isNaN, isFinite, Number, String, Boolean
  • Array: push, pop, length 等基本数组操作
  • Object: 基本对象操作和属性访问
  • Date: 日期对象基本功能 (new Date(), getTime(), etc.)
  • JSON: parse 和 stringify 方法 (通过外部传入)

❌ 暂不支持

  • ES6+ 语法 (const, let, 箭头函数, 类, 模板字符串)
  • 异步操作 (Promise, async/await, setTimeout)
  • 正则表达式字面量
  • 模块系统 (import/export)
  • 错误处理 (try/catch/finally)

🏗️ 架构设计

执行流程

JavaScript源码 → Babel AST → 字节码编译 → 虚拟机执行 → 结果输出

虚拟机组件

┌─────────────────────────────────────┐
│            JSVMP 架构               │
├─────────────────────────────────────┤
│  Parser (Babel)     │  Compiler     │
│  ┌─────────────┐    │  ┌─────────┐  │
│  │ JavaScript  │───→│  │   AST   │  │
│  │   Source    │    │  │    ↓    │  │
│  └─────────────┘    │  │Bytecode │  │
│                     │  └─────────┘  │
├─────────────────────┼───────────────┤
│       Virtual Machine (VM)          │
│  ┌─────────────┐    ┌─────────────┐ │
│  │   Stack     │    │ Call Stack  │ │
│  │ ┌─────────┐ │    │ ┌─────────┐ │ │
│  │ │ Value 3 │ │    │ │ Frame 2 │ │ │
│  │ ├─────────┤ │    │ ├─────────┤ │ │
│  │ │ Value 2 │ │    │ │ Frame 1 │ │ │
│  │ ├─────────┤ │    │ └─────────┘ │ │
│  │ │ Value 1 │ │                    │
│  │ └─────────┘ │                    │
│  └─────────────┘                    │
└─────────────────────────────────────┘

指令集

支持 40+ 字节码指令:

类别 指令 描述
栈操作 PUSH, POP, DUP 栈基本操作
算术运算 ADD, SUB, MUL, DIV, MOD 数学运算
位运算 BIT_AND, BIT_OR, SHL, SHR 位操作
比较运算 EQ, NE, LT, GT, LE, GE 比较操作
控制流 JMP, JIF, JNF, CALL, RET 跳转和调用
变量操作 LOAD, STORE, DECLARE 变量管理
对象操作 GET_PROP, SET_PROP, NEW_OBJ 对象操作
数组操作 GET_ELEM, SET_ELEM, NEW_ARR 数组操作

📥 外部变量传入

JSVMP 的一大特色是支持安全地传入外部变量和函数到虚拟机环境中执行。

支持的数据类型

类型 示例 说明
基本类型 { name: "张三", age: 25 } 字符串、数字、布尔值
对象 { user: { id: 1, name: "Alice" } } 普通对象、嵌套对象
数组 { numbers: [1, 2, 3, 4, 5] } 任意类型的数组
函数 { calculate: (x) => x * 2 } 普通函数、箭头函数
类实例 { api: new APIClient() } 完整的类对象

使用方式

const vm = new JSVMP();

// 方式1: 直接传入
const result = vm.run('name + " - " + age', {
    name: "张三",
    age: 25
});

// 方式2: 复杂API传入
const result2 = vm.run(`
    var user = api.getUser(123);
    var formatted = utils.formatDate(new Date());
    user.name + " - " + formatted
`, {
    api: {
        getUser: (id) => ({ id, name: `用户${id}` }),
        saveUser: (user) => { /* 保存逻辑 */ }
    },
    utils: {
        formatDate: (date) => date.toLocaleDateString('zh-CN')
    }
});

安全特性

  • 沙盒隔离: 虚拟机无法访问未传入的外部变量
  • 权限控制: 只能访问显式传入的API
  • 类型安全: 支持所有JavaScript数据类型
  • 引用保持: 对象引用保持不变,可以修改外部对象
  • 函数绑定: 函数的this绑定和作用域保持正确

最佳实践

  1. API封装: 将复杂逻辑封装成函数传入
  2. 权限最小化: 只传入必要的数据和函数
  3. 错误处理: 外部函数应包含适当的错误处理
  4. 性能优化: 避免传入过大的对象

详细文档请参考: docs/external-variables.md

📊 性能特性

  • 启动速度: ~5ms 初始化时间
  • 执行效率: 比原生 JavaScript 慢 3-5 倍
  • 内存占用: 最小化栈式架构,约 1-2MB 基础内存
  • 外部调用: 接近原生性能的外部函数调用
  • 安全性: 完全隔离的执行环境,无性能损失
  • 调试性: 详细的执行追踪和错误定位

🎯 使用场景

安全执行

  • 🔒 代码沙盒: 安全执行用户提交的代码,防止恶意操作
  • 🧪 测试环境: 隔离的代码测试执行,不影响主环境
  • 🛡️ 权限控制: 通过外部变量控制代码访问权限

教学和培训

  • 🎓 教学工具: JavaScript 语言教学和演示
  • 📚 代码演示: 在线代码编辑器和运行环境
  • 🔍 代码分析: 静态分析和代码理解工具

业务应用

  • 📊 脚本引擎: 嵌入式脚本执行引擎
  • 🔧 配置化: 通过脚本实现业务逻辑配置
  • 📋 规则引擎: 动态业务规则执行
  • 📊 数据处理: 安全的数据转换和计算
  • 🎯 模板引擎: 基于数据的模板渲染

集成场景

  • 🌐 Web应用: 浏览器中的安全脚本执行
  • 📱 移动应用: 跨平台脚本执行引擎
  • 🖥️ 桌面应用: Electron等环境中的脚本支持
  • ☁️ 云函数: serverless环境中的代码执行

📝 示例项目

查看 examples/ 目录获取完整示例:

在线体验

打开 examples/web-usage.html 在浏览器中体验所有功能:

  • 🔗 闭包和作用域演示
  • 📐 斐波那契数列计算
  • 🏛️ 面向对象编程
  • ⚡ 函数式编程
  • 📥 外部变量传入

🧪 测试

# 运行所有测试
npm test

# 运行示例测试
npm run test:examples

# 运行基本示例
npm run dev

🛠️ 开发

本地开发

# 克隆仓库
git clone https://github.com/yourusername/jsvmp.git
cd jsvmp

# 安装依赖
npm install

# 开发模式构建
npm run build:dev

# 生产模式构建
npm run build

# 运行测试
npm test

项目结构

jsvmp/
├── src/                # 源代码
│   ├── index.js       # 主入口文件
│   ├── parser.js      # JavaScript 解析器
│   ├── compiler.js    # AST 到字节码编译器
│   ├── vm.js          # 虚拟机执行引擎
│   ├── opcodes.js     # 字节码指令定义
│   └── lexer.js       # 词法分析器
├── examples/          # 使用示例
├── tests/             # 测试文件
├── types/             # TypeScript 定义
├── dist/              # 构建输出
├── package.json       # 项目配置
├── webpack.config.js  # 构建配置
└── README.md          # 项目文档

🤝 贡献

欢迎贡献代码!请查看 贡献指南

  1. Fork 本仓库
  2. 创建特性分支: git checkout -b feature/amazing-feature
  3. 提交更改: git commit -m 'Add amazing feature'
  4. 推送分支: git push origin feature/amazing-feature
  5. 提交 Pull Request

📄 许可证

本项目采用 MIT 许可证 - 详见 LICENSE 文件。

🙏 致谢


⭐ 如果这个项目对你有帮助,请给个 Star!

About

一个基于栈式架构的 JavaScript 虚拟机,支持在沙盒环境中安全执行 JavaScript 代码。使用 Babel AST 解析和字节码编译技术,提供完整的 JavaScript 语法支持。

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors