2

我想知道下面描述的步骤是如何完成的:

  1. 如何将 JS 源文件(带有两个函数 funcA() 和 funcB() 的 test.js)转换为字节码?
  2. 如何将生成的字节码加载到 duktape 中并调用其中一个函数,比如 funcA()?

谢谢。

测试.js:

function funcA() {
    print("funcA()");
}

function funcB() {
    print("funcB()");
}

主文件

int main() {
    duk_context* ctx = duk_create_heap_default();

    std::string byteCodeBuff; // buffer where to save the byte code;

    { // generate the bytecode from 'sourceFilePath'

        const char* sourceCodeFilePath = "test.js"; // contains the JS code
        //  Step 1 How to 'dump' the 'sourceFilePath' to bytecode buffer ???

        // get the duktape bytecode
        duk_size_t bufferSize = 0;
        const char* bytecode = (const char*)duk_get_buffer(ctx, -1, &bufferSize);

        // save the bytecode to byteCodeBuff 
        byteCodeBuff.assign(bytecode,bufferSize);

        duk_pop(ctx);  // bytecode buffer
    }

    { // load the bytecode into duktape

        const size_t length = byteCodeBuff.size();    // bytecode length
        const char* bytecode = &byteCodeBuff.front(); // pointer to bytecode 

        char* dukBuff = (char*)duk_push_fixed_buffer(ctx, length); // push a duk buffer to stack
        memcpy(dukBuff, bytecode, length); // copy the bytecode to the duk buffer

        // Step 2 ??? How start using the bytecode
        // ??? How to invoke funcA()
        // ??? How to invoke funcB()
    }

    duk_destroy_heap(ctx);

    return 0;
}
4

1 回答 1

1

duk_dump_functionduk_load_function是 Duktape 提供的用于转换字节码和从字节码转换的函数:

首先,只需加载您的文件:

// 步骤 1 (a):
char* 源代码;
int sourceLen;
{ // 从文件加载(请原谅没有捕获错误...)
    ifstream fscript(sourceCodeFilePath,ios::in | ios::binary);
    fscript.seekg(0,ios::end);
    sourceLen= fscript.tellg();
    缓冲区 = 新字符 [sourceLen];
    fscript.seekg(0);
    fscript.read(sourceCode,sourceLen);
}

然后,在编译 javascript 时,脚本将作为“函数”(实际上是一段未执行的全局代码)编译到堆栈中:

// 步骤 1 (b):

// 编译源代码
duk_compile_lstring(ctx,0,sourceCode,sourceLen); // 编译为 ECMAScript 函数并将其放在栈顶

// 将代码转储到缓冲区
duk_dump_function(ctx); // 用它的字节码替换栈顶函数

从这一点开始,您的其余代码应该获取堆栈顶部的缓冲区。

至于恢复它:

// 步骤 2 (a):
// 用原来的函数替换栈顶的缓冲区
duk_load_function(ctx);

// 因为这是一个全局脚本,所以必须在调用各个函数之前执行
duk_call(ctx,0); // 或许可以考虑使用 duk_pcall()

此时,ctx堆的全局对象现在包含属性funcAfuncB。这些可以这样获取和调用:

// 步骤 2 (b):
// 将全局对象压入堆栈以获取其属性
duk_push_global_object(ctx);

// 获取名为“funcA”的函数并将其压入堆栈
duk_get_prop_string(ctx,-1,"funcA"); //键名/全局函数名

duk_require_function(ctx,-1); // 在调用它之前要求这是一个函数

// 现在调用它!
// duk_push_* 参数在这里
duk_call(ctx,0); // 0: 参数个数

// duk_get_* (ctx,-1); 获取返回值

//弹出函数返回值
duk_pop(ctx);

// 当前栈顶:全局对象

// 获取下一个函数
duk_get_prop_string(ctx,-1,"funcB");

// 要求它是一个函数
duk_require_function(ctx,-1);

// 调用它!
duk_call(ctx,0);

// 弹出返回和全局对象出栈
duk_pop_2(ctx);
于 2017-05-15T00:46:37.940 回答