Skip to content

Instantly share code, notes, and snippets.

@ngot
Last active November 4, 2024 13:07
Show Gist options
  • Select an option

  • Save ngot/4e363c08c1a912f3f10fda882a9e3956 to your computer and use it in GitHub Desktop.

Select an option

Save ngot/4e363c08c1a912f3f10fda882a9e3956 to your computer and use it in GitHub Desktop.

Revisions

  1. ngot revised this gist Sep 14, 2017. 1 changed file with 13 additions and 0 deletions.
    13 changes: 13 additions & 0 deletions multi-thread.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    start(() => {
    while(true)
    {
    print("a");
    sleep(1000);
    }
    })

    while(true)
    {
    print("b");
    sleep(1000);
    }
  2. ngot renamed this gist Sep 14, 2017. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. ngot revised this gist Sep 14, 2017. 1 changed file with 431 additions and 65 deletions.
    496 changes: 431 additions & 65 deletions demo.cpp
    Original file line number Diff line number Diff line change
    @@ -1,109 +1,164 @@
    #include <stdio.h>
    #include <stdlib.h>
    #include <iostream>
    // Copyright 2012 the V8 project authors. All rights reserved.
    // Redistribution and use in source and binary forms, with or without
    // modification, are permitted provided that the following conditions are
    // met:
    //
    // * Redistributions of source code must retain the above copyright
    // notice, this list of conditions and the following disclaimer.
    // * Redistributions in binary form must reproduce the above
    // copyright notice, this list of conditions and the following
    // disclaimer in the documentation and/or other materials provided
    // with the distribution.
    // * Neither the name of Google Inc. nor the names of its
    // contributors may be used to endorse or promote products derived
    // from this software without specific prior written permission.
    //
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    #include <v8.h>

    #include <libplatform/libplatform.h>

    #include <assert.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #include <chrono>
    #include <thread>
    #include <future>
    #include <iostream>

    #include "libplatform/libplatform.h"
    #include "v8.h"
    /**
    * This sample program shows how to implement a simple javascript shell
    * based on V8. This includes initializing V8 with command line options,
    * creating global functions, compiling and executing strings.
    *
    * For a more sophisticated shell, consider using the debug shell D8.
    */

    v8::Local<v8::Context> CreateShellContext(v8::Isolate *isolate);
    void RunShell(v8::Local<v8::Context> context, v8::Platform *platform);
    int RunMain(v8::Isolate *isolate, v8::Platform *platform, int argc,
    char *argv[]);
    bool ExecuteString(v8::Isolate *isolate, v8::Local<v8::String> source,
    v8::Local<v8::Value> name, bool print_result,
    bool report_exceptions);
    void Print(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Read(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Load(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Quit(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Version(const v8::FunctionCallbackInfo<v8::Value> &args);
    v8::MaybeLocal<v8::String> ReadFile(v8::Isolate *isolate, const char *name);
    void ReportException(v8::Isolate *isolate, v8::TryCatch *handler);

    v8::Local<v8::Context> CreateContext(v8::Isolate *isolate);
    void Start(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Print(const v8::FunctionCallbackInfo<v8::Value> &args);

    v8::Global<v8::Context> g_context;
    v8::Isolate *isolate = nullptr;

    // Extracts a C string from a V8 Utf8Value.
    const char *ToCString(const v8::String::Utf8Value &value)
    {
    return *value ? *value : "<string conversion failed>";
    }
    static bool run_shell;

    int main(int argc, char *argv[])
    {
    // Initialize V8.
    v8::V8::InitializeICUDefaultLocation(argv[0]);
    v8::V8::InitializeExternalStartupData(argv[0]);
    v8::Platform *platform = v8::platform::CreateDefaultPlatform();
    v8::V8::InitializePlatform(platform);
    v8::V8::Initialize();

    // Create a new Isolate and make it the current one.
    v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
    v8::Isolate::CreateParams create_params;
    create_params.array_buffer_allocator =
    v8::ArrayBuffer::Allocator::NewDefaultAllocator();

    isolate = v8::Isolate::New(create_params);

    run_shell = (argc == 1);
    int result;
    {
    v8::Locker locker(isolate);
    v8::Isolate::Scope isolate_scope(isolate);

    // Create a stack-allocated handle scope.
    v8::HandleScope handle_scope(isolate);

    // Create a new context.
    v8::Local<v8::Context> context = CreateContext(isolate);
    v8::Local<v8::Context> context = CreateShellContext(isolate);
    g_context.Reset(isolate, context);

    // Enter the context for compiling and running the hello world script.
    if (context.IsEmpty())
    {
    fprintf(stderr, "Error creating context\n");
    return 1;
    }
    v8::Context::Scope context_scope(context);

    // Create a string containing the JavaScript source code.
    v8::Local<v8::String> source =
    v8::String::NewFromUtf8(isolate, "start(() => {print('this is fn!!!')});sleep(2000);",
    v8::NewStringType::kNormal)
    .ToLocalChecked();

    // Compile the source code.
    v8::Local<v8::Script> script =
    v8::Script::Compile(context, source).ToLocalChecked();

    // Run the script to get the result.
    v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();

    // Convert the result to an UTF8 string and print it.
    v8::String::Utf8Value utf8(isolate, result);
    printf("%s\n", *utf8);
    result = RunMain(isolate, platform, argc, argv);
    if (run_shell)
    RunShell(context, platform);
    }

    // Dispose the isolate and tear down V8.
    isolate->Dispose();
    v8::V8::Dispose();
    v8::V8::ShutdownPlatform();
    delete platform;
    delete create_params.array_buffer_allocator;
    return 0;
    return result;
    }

    v8::Local<v8::Context> CreateContext(v8::Isolate *isolate)
    // Extracts a C string from a V8 Utf8Value.
    const char *ToCString(const v8::String::Utf8Value &value)
    {
    return *value ? *value : "<string conversion failed>";
    }

    // Creates a new execution environment containing the built-in
    // functions.
    v8::Local<v8::Context> CreateShellContext(v8::Isolate *isolate)
    {
    // Create a template for the global object.
    v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
    // Bind the global 'start' function to the C++ Print callback.
    // Bind the global 'print' function to the C++ Print callback.
    global->Set(
    v8::String::NewFromUtf8(isolate, "start", v8::NewStringType::kNormal)
    v8::String::NewFromUtf8(isolate, "print", v8::NewStringType::kNormal)
    .ToLocalChecked(),
    v8::FunctionTemplate::New(isolate, Start));
    v8::FunctionTemplate::New(isolate, Print));
    // Bind the global 'read' function to the C++ Read callback.
    global->Set(v8::String::NewFromUtf8(
    isolate, "read", v8::NewStringType::kNormal)
    .ToLocalChecked(),
    v8::FunctionTemplate::New(isolate, Read));
    // Bind the global 'load' function to the C++ Load callback.
    global->Set(v8::String::NewFromUtf8(
    isolate, "load", v8::NewStringType::kNormal)
    .ToLocalChecked(),
    v8::FunctionTemplate::New(isolate, Load));
    // Bind the 'quit' function
    global->Set(v8::String::NewFromUtf8(
    isolate, "quit", v8::NewStringType::kNormal)
    .ToLocalChecked(),
    v8::FunctionTemplate::New(isolate, Quit));
    // Bind the 'version' function
    global->Set(
    v8::String::NewFromUtf8(isolate, "version", v8::NewStringType::kNormal)
    .ToLocalChecked(),
    v8::FunctionTemplate::New(isolate, Version));

    // Bind the global 'sleep' function to the C++ Print callback.
    // Bind the 'sleep' function
    global->Set(
    v8::String::NewFromUtf8(isolate, "sleep", v8::NewStringType::kNormal)
    .ToLocalChecked(),
    v8::FunctionTemplate::New(isolate, Sleep));

    // Bind the global 'sleep' function to the C++ Print callback.
    // Bind the 'start' function
    global->Set(
    v8::String::NewFromUtf8(isolate, "print", v8::NewStringType::kNormal)
    v8::String::NewFromUtf8(isolate, "start", v8::NewStringType::kNormal)
    .ToLocalChecked(),
    v8::FunctionTemplate::New(isolate, Print));
    v8::FunctionTemplate::New(isolate, Start));

    return v8::Context::New(isolate, NULL, global);
    }
    @@ -133,52 +188,363 @@ void Print(const v8::FunctionCallbackInfo<v8::Value> &args)
    fflush(stdout);
    }

    // The callback that is invoked by v8 whenever the JavaScript 'read'
    // function is called. This function loads the content of the file named in
    // the argument into a JavaScript string.
    void Read(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    if (args.Length() != 1)
    {
    args.GetIsolate()->ThrowException(
    v8::String::NewFromUtf8(args.GetIsolate(), "Bad parameters",
    v8::NewStringType::kNormal)
    .ToLocalChecked());
    return;
    }
    v8::String::Utf8Value file(args.GetIsolate(), args[0]);
    if (*file == NULL)
    {
    args.GetIsolate()->ThrowException(
    v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file",
    v8::NewStringType::kNormal)
    .ToLocalChecked());
    return;
    }
    v8::Local<v8::String> source;
    if (!ReadFile(args.GetIsolate(), *file).ToLocal(&source))
    {
    args.GetIsolate()->ThrowException(
    v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file",
    v8::NewStringType::kNormal)
    .ToLocalChecked());
    return;
    }

    args.GetReturnValue().Set(source);
    }

    // The callback that is invoked by v8 whenever the JavaScript 'load'
    // function is called. Loads, compiles and executes its argument
    // JavaScript file.
    void Load(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    for (int i = 0; i < args.Length(); i++)
    {
    v8::HandleScope handle_scope(args.GetIsolate());
    v8::String::Utf8Value file(args.GetIsolate(), args[i]);
    if (*file == NULL)
    {
    args.GetIsolate()->ThrowException(
    v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file",
    v8::NewStringType::kNormal)
    .ToLocalChecked());
    return;
    }
    v8::Local<v8::String> source;
    if (!ReadFile(args.GetIsolate(), *file).ToLocal(&source))
    {
    args.GetIsolate()->ThrowException(
    v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file",
    v8::NewStringType::kNormal)
    .ToLocalChecked());
    return;
    }
    if (!ExecuteString(args.GetIsolate(), source, args[i], false, false))
    {
    args.GetIsolate()->ThrowException(
    v8::String::NewFromUtf8(args.GetIsolate(), "Error executing file",
    v8::NewStringType::kNormal)
    .ToLocalChecked());
    return;
    }
    }
    }

    // The callback that is invoked by v8 whenever the JavaScript 'quit'
    // function is called. Quits.
    void Quit(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    // If not arguments are given args[0] will yield undefined which
    // converts to the integer value 0.
    int exit_code =
    args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromMaybe(0);
    fflush(stdout);
    fflush(stderr);
    exit(exit_code);
    }

    void Version(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    args.GetReturnValue().Set(
    v8::String::NewFromUtf8(args.GetIsolate(), v8::V8::GetVersion(),
    v8::NewStringType::kNormal)
    .ToLocalChecked());
    }

    // Reads a file into a v8 string.
    v8::MaybeLocal<v8::String> ReadFile(v8::Isolate *isolate, const char *name)
    {
    FILE *file = fopen(name, "rb");
    if (file == NULL)
    return v8::MaybeLocal<v8::String>();

    fseek(file, 0, SEEK_END);
    size_t size = ftell(file);
    rewind(file);

    char *chars = new char[size + 1];
    chars[size] = '\0';
    for (size_t i = 0; i < size;)
    {
    i += fread(&chars[i], 1, size - i, file);
    if (ferror(file))
    {
    fclose(file);
    return v8::MaybeLocal<v8::String>();
    }
    }
    fclose(file);
    v8::MaybeLocal<v8::String> result = v8::String::NewFromUtf8(
    isolate, chars, v8::NewStringType::kNormal, static_cast<int>(size));
    delete[] chars;
    return result;
    }

    // Process remaining command line arguments and execute files
    int RunMain(v8::Isolate *isolate, v8::Platform *platform, int argc,
    char *argv[])
    {
    for (int i = 1; i < argc; i++)
    {
    const char *str = argv[i];
    if (strcmp(str, "--shell") == 0)
    {
    run_shell = true;
    }
    else if (strcmp(str, "-f") == 0)
    {
    // Ignore any -f flags for compatibility with the other stand-
    // alone JavaScript engines.
    continue;
    }
    else if (strncmp(str, "--", 2) == 0)
    {
    fprintf(stderr,
    "Warning: unknown flag %s.\nTry --help for options\n", str);
    }
    else if (strcmp(str, "-e") == 0 && i + 1 < argc)
    {
    // Execute argument given to -e option directly.
    v8::Local<v8::String> file_name =
    v8::String::NewFromUtf8(isolate, "unnamed",
    v8::NewStringType::kNormal)
    .ToLocalChecked();
    v8::Local<v8::String> source;
    if (!v8::String::NewFromUtf8(isolate, argv[++i],
    v8::NewStringType::kNormal)
    .ToLocal(&source))
    {
    return 1;
    }
    bool success = ExecuteString(isolate, source, file_name, false, true);
    while (v8::platform::PumpMessageLoop(platform, isolate))
    continue;
    if (!success)
    return 1;
    }
    else
    {
    // Use all other arguments as names of files to load and run.
    v8::Local<v8::String> file_name =
    v8::String::NewFromUtf8(isolate, str, v8::NewStringType::kNormal)
    .ToLocalChecked();
    v8::Local<v8::String> source;
    if (!ReadFile(isolate, str).ToLocal(&source))
    {
    fprintf(stderr, "Error reading '%s'\n", str);
    continue;
    }
    bool success = ExecuteString(isolate, source, file_name, false, true);
    while (v8::platform::PumpMessageLoop(platform, isolate))
    continue;
    if (!success)
    return 1;
    }
    }
    return 0;
    }

    // The read-eval-execute loop of the shell.
    void RunShell(v8::Local<v8::Context> context, v8::Platform *platform)
    {
    fprintf(stderr, "V8 version %s [sample shell]\n", v8::V8::GetVersion());
    static const int kBufferSize = 256;
    // Enter the execution environment before evaluating any code.
    v8::Context::Scope context_scope(context);
    v8::Local<v8::String> name(
    v8::String::NewFromUtf8(context->GetIsolate(), "(shell)",
    v8::NewStringType::kNormal)
    .ToLocalChecked());
    while (true)
    {
    char buffer[kBufferSize];
    fprintf(stderr, "> ");
    char *str = fgets(buffer, kBufferSize, stdin);
    if (str == NULL)
    break;
    v8::HandleScope handle_scope(context->GetIsolate());
    ExecuteString(
    context->GetIsolate(),
    v8::String::NewFromUtf8(context->GetIsolate(), str,
    v8::NewStringType::kNormal)
    .ToLocalChecked(),
    name, true, true);
    while (v8::platform::PumpMessageLoop(platform, context->GetIsolate()))
    continue;
    }
    fprintf(stderr, "\n");
    }

    // Executes a string within the current v8 context.
    bool ExecuteString(v8::Isolate *isolate, v8::Local<v8::String> source,
    v8::Local<v8::Value> name, bool print_result,
    bool report_exceptions)
    {
    v8::HandleScope handle_scope(isolate);
    v8::TryCatch try_catch(isolate);
    v8::ScriptOrigin origin(name);
    v8::Local<v8::Context> context(isolate->GetCurrentContext());
    v8::Local<v8::Script> script;
    if (!v8::Script::Compile(context, source, &origin).ToLocal(&script))
    {
    // Print errors that happened during compilation.
    if (report_exceptions)
    ReportException(isolate, &try_catch);
    return false;
    }
    else
    {
    v8::Local<v8::Value> result;
    if (!script->Run(context).ToLocal(&result))
    {
    assert(try_catch.HasCaught());
    // Print errors that happened during execution.
    if (report_exceptions)
    ReportException(isolate, &try_catch);
    return false;
    }
    else
    {
    assert(!try_catch.HasCaught());
    if (print_result && !result->IsUndefined())
    {
    // If all went well and the result wasn't undefined then print
    // the returned value.
    v8::String::Utf8Value str(isolate, result);
    const char *cstr = ToCString(str);
    printf("%s\n", cstr);
    }
    return true;
    }
    }
    }

    void ReportException(v8::Isolate *isolate, v8::TryCatch *try_catch)
    {
    v8::HandleScope handle_scope(isolate);
    v8::String::Utf8Value exception(isolate, try_catch->Exception());
    const char *exception_string = ToCString(exception);
    v8::Local<v8::Message> message = try_catch->Message();
    if (message.IsEmpty())
    {
    // V8 didn't provide any extra information about this error; just
    // print the exception.
    fprintf(stderr, "%s\n", exception_string);
    }
    else
    {
    // Print (filename):(line number): (message).
    v8::String::Utf8Value filename(isolate,
    message->GetScriptOrigin().ResourceName());
    v8::Local<v8::Context> context(isolate->GetCurrentContext());
    const char *filename_string = ToCString(filename);
    int linenum = message->GetLineNumber(context).FromJust();
    fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
    // Print line of source code.
    v8::String::Utf8Value sourceline(
    isolate, message->GetSourceLine(context).ToLocalChecked());
    const char *sourceline_string = ToCString(sourceline);
    fprintf(stderr, "%s\n", sourceline_string);
    // Print wavy underline (GetUnderline is deprecated).
    int start = message->GetStartColumn(context).FromJust();
    for (int i = 0; i < start; i++)
    {
    fprintf(stderr, " ");
    }
    int end = message->GetEndColumn(context).FromJust();
    for (int i = start; i < end; i++)
    {
    fprintf(stderr, "^");
    }
    fprintf(stderr, "\n");
    v8::Local<v8::Value> stack_trace_string;
    if (try_catch->StackTrace(context).ToLocal(&stack_trace_string) &&
    stack_trace_string->IsString() &&
    v8::Local<v8::String>::Cast(stack_trace_string)->Length() > 0)
    {
    v8::String::Utf8Value stack_trace(isolate, stack_trace_string);
    const char *stack_trace_string = ToCString(stack_trace);
    fprintf(stderr, "%s\n", stack_trace_string);
    }
    }
    }

    void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    std::cout << "Sleep 0" << std::endl;
    // std::cout << "Sleep 0" << std::endl;
    v8::Unlocker unlocker(isolate);
    std::cout << "Sleep 1" << std::endl;
    // std::cout << "Sleep 1" << std::endl;
    v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate, g_context);
    std::cout << "Sleep 2" << std::endl;
    // std::cout << "Sleep 2" << std::endl;
    int time = args[0]->Int32Value(context).FromMaybe(0);
    std::this_thread::sleep_for(std::chrono::milliseconds(time));
    std::cout << "Sleep 3" << std::endl;
    // std::cout << "Sleep 3" << std::endl;
    }

    void do_work(v8::Global<v8::Function> func)
    {
    std::cout << "do_work 0" << std::endl;
    // std::cout << "do_work 0" << std::endl;

    v8::Locker locker(isolate);
    std::cout << "do_work 1" << std::endl;
    // std::cout << "do_work 1" << std::endl;

    v8::Isolate::Scope isolate_scope(isolate);
    std::cout << "do_work 2" << std::endl;
    // std::cout << "do_work 2" << std::endl;

    v8::HandleScope handle_scope(isolate);
    std::cout << "do_work 3" << std::endl;
    // std::cout << "do_work 3" << std::endl;

    v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate, g_context);

    v8::Context::Scope context_scope(
    v8::Local<v8::Context>::New(isolate, context));
    std::cout << "do_work 4" << std::endl;
    // std::cout << "do_work 4" << std::endl;

    v8::Local<v8::Function> fn = v8::Local<v8::Function>::New(isolate, func);
    std::cout << "do_work 5" << std::endl;
    // std::cout << "do_work 5" << std::endl;

    v8::Local<v8::Value> v = fn->Call(v8::Undefined(isolate), 0, NULL);
    std::cout << "do_work 6" << std::endl;
    // std::cout << "do_work 6" << std::endl;
    }

    void Start(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    std::cout << "Start start" << std::endl;
    // std::cout << "Start start" << std::endl;
    v8::Global<v8::Function> fn;
    v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(args[0]);
    fn.Reset(isolate, f);

    std::thread new_thread(do_work, std::move(fn));
    new_thread.detach();
    std::cout << "Start end" << std::endl;
    // std::cout << "Start end" << std::endl;
    }
  4. ngot revised this gist Sep 14, 2017. 1 changed file with 18 additions and 10 deletions.
    28 changes: 18 additions & 10 deletions demo.cpp
    Original file line number Diff line number Diff line change
    @@ -17,7 +17,7 @@ void Start(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Print(const v8::FunctionCallbackInfo<v8::Value> &args);

    v8::Local<v8::Context> g_context;
    v8::Global<v8::Context> g_context;
    v8::Isolate *isolate = nullptr;

    // Extracts a C string from a V8 Utf8Value.
    @@ -50,23 +50,24 @@ int main(int argc, char *argv[])
    v8::HandleScope handle_scope(isolate);

    // Create a new context.
    g_context = CreateContext(isolate);
    v8::Local<v8::Context> context = CreateContext(isolate);
    g_context.Reset(isolate, context);

    // Enter the context for compiling and running the hello world script.
    v8::Context::Scope context_scope(g_context);
    v8::Context::Scope context_scope(context);

    // Create a string containing the JavaScript source code.
    v8::Local<v8::String> source =
    v8::String::NewFromUtf8(isolate, "start(() => {print('this is fn!!!')});sleep();",
    v8::String::NewFromUtf8(isolate, "start(() => {print('this is fn!!!')});sleep(2000);",
    v8::NewStringType::kNormal)
    .ToLocalChecked();

    // Compile the source code.
    v8::Local<v8::Script> script =
    v8::Script::Compile(g_context, source).ToLocalChecked();
    v8::Script::Compile(context, source).ToLocalChecked();

    // Run the script to get the result.
    v8::Local<v8::Value> result = script->Run(g_context).ToLocalChecked();
    v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();

    // Convert the result to an UTF8 string and print it.
    v8::String::Utf8Value utf8(isolate, result);
    @@ -134,9 +135,14 @@ void Print(const v8::FunctionCallbackInfo<v8::Value> &args)

    void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    std::cout << "sleep 1" << std::endl;
    std::cout << "Sleep 0" << std::endl;
    v8::Unlocker unlocker(isolate);
    std::cout << "sleep 2" << std::endl;
    std::cout << "Sleep 1" << std::endl;
    v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate, g_context);
    std::cout << "Sleep 2" << std::endl;
    int time = args[0]->Int32Value(context).FromMaybe(0);
    std::this_thread::sleep_for(std::chrono::milliseconds(time));
    std::cout << "Sleep 3" << std::endl;
    }

    void do_work(v8::Global<v8::Function> func)
    @@ -152,13 +158,15 @@ void do_work(v8::Global<v8::Function> func)
    v8::HandleScope handle_scope(isolate);
    std::cout << "do_work 3" << std::endl;

    v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate, g_context);

    v8::Context::Scope context_scope(
    v8::Local<v8::Context>::New(isolate, g_context));
    v8::Local<v8::Context>::New(isolate, context));
    std::cout << "do_work 4" << std::endl;

    v8::Local<v8::Function> fn = v8::Local<v8::Function>::New(isolate, func);
    std::cout << "do_work 5" << std::endl;

    v8::Local<v8::Value> v = fn->Call(v8::Undefined(isolate), 0, NULL);
    std::cout << "do_work 6" << std::endl;
    }
  5. ngot revised this gist Sep 14, 2017. 1 changed file with 18 additions and 18 deletions.
    36 changes: 18 additions & 18 deletions demo.cpp
    Original file line number Diff line number Diff line change
    @@ -17,6 +17,9 @@ void Start(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Print(const v8::FunctionCallbackInfo<v8::Value> &args);

    v8::Local<v8::Context> g_context;
    v8::Isolate *isolate = nullptr;

    // Extracts a C string from a V8 Utf8Value.
    const char *ToCString(const v8::String::Utf8Value &value)
    {
    @@ -37,7 +40,7 @@ int main(int argc, char *argv[])
    create_params.array_buffer_allocator =
    v8::ArrayBuffer::Allocator::NewDefaultAllocator();

    v8::Isolate *isolate = v8::Isolate::New(create_params);
    isolate = v8::Isolate::New(create_params);

    {
    v8::Locker locker(isolate);
    @@ -47,10 +50,10 @@ int main(int argc, char *argv[])
    v8::HandleScope handle_scope(isolate);

    // Create a new context.
    v8::Local<v8::Context> context = CreateContext(isolate);
    g_context = CreateContext(isolate);

    // Enter the context for compiling and running the hello world script.
    v8::Context::Scope context_scope(context);
    v8::Context::Scope context_scope(g_context);

    // Create a string containing the JavaScript source code.
    v8::Local<v8::String> source =
    @@ -60,10 +63,10 @@ int main(int argc, char *argv[])

    // Compile the source code.
    v8::Local<v8::Script> script =
    v8::Script::Compile(context, source).ToLocalChecked();
    v8::Script::Compile(g_context, source).ToLocalChecked();

    // Run the script to get the result.
    v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
    v8::Local<v8::Value> result = script->Run(g_context).ToLocalChecked();

    // Convert the result to an UTF8 string and print it.
    v8::String::Utf8Value utf8(isolate, result);
    @@ -131,14 +134,12 @@ void Print(const v8::FunctionCallbackInfo<v8::Value> &args)

    void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    v8::Isolate *isolate = args.GetIsolate();
    std::cout << "sleep 1" << std::endl;
    v8::Unlocker unlocker(isolate);
    std::cout << "sleep 2" << std::endl;
    }

    void do_work(v8::Isolate *isolate, v8::Local<v8::Context> &context,
    const v8::FunctionCallbackInfo<v8::Value> &args)
    void do_work(v8::Global<v8::Function> func)
    {
    std::cout << "do_work 0" << std::endl;

    @@ -151,26 +152,25 @@ void do_work(v8::Isolate *isolate, v8::Local<v8::Context> &context,
    v8::HandleScope handle_scope(isolate);
    std::cout << "do_work 3" << std::endl;

    // v8::Context::Scope context_scope(
    // v8::Local<v8::Context>::New(isolate, context));
    // std::cout << "do_work 4" << std::endl;
    v8::Context::Scope context_scope(
    v8::Local<v8::Context>::New(isolate, g_context));
    std::cout << "do_work 4" << std::endl;

    v8::Local<v8::Function> fn = v8::Local<v8::Function>::Cast(args[0]);
    v8::Local<v8::Function> fn = v8::Local<v8::Function>::New(isolate, func);
    std::cout << "do_work 5" << std::endl;

    v8::Local<v8::Value> v = fn->Call(v8::Undefined(isolate), 0, NULL);
    std::cout << "do_work 6" << std::endl;
    }

    void Start(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    std::cout << "Start start" << std::endl;
    v8::Isolate *isolate = args.GetIsolate();
    v8::Global<v8::Function> fn;
    v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(args[0]);
    fn.Reset(isolate, f);

    v8::Local<v8::Context> context = isolate->GetCurrentContext();

    std::thread new_thread(do_work, isolate, std::ref(context), std::ref(args));
    std::thread new_thread(do_work, std::move(fn));
    new_thread.detach();

    std::cout << "Start end" << std::endl;
    }
  6. ngot revised this gist Sep 14, 2017. 1 changed file with 57 additions and 12 deletions.
    69 changes: 57 additions & 12 deletions demo.cpp
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,9 @@
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #include <chrono>
    #include <thread>
    @@ -13,6 +15,13 @@
    v8::Local<v8::Context> CreateContext(v8::Isolate *isolate);
    void Start(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Print(const v8::FunctionCallbackInfo<v8::Value> &args);

    // Extracts a C string from a V8 Utf8Value.
    const char *ToCString(const v8::String::Utf8Value &value)
    {
    return *value ? *value : "<string conversion failed>";
    }

    int main(int argc, char *argv[])
    {
    @@ -45,7 +54,7 @@ int main(int argc, char *argv[])

    // Create a string containing the JavaScript source code.
    v8::Local<v8::String> source =
    v8::String::NewFromUtf8(isolate, "start();sleep(2);",
    v8::String::NewFromUtf8(isolate, "start(() => {print('this is fn!!!')});sleep();",
    v8::NewStringType::kNormal)
    .ToLocalChecked();

    @@ -86,9 +95,40 @@ v8::Local<v8::Context> CreateContext(v8::Isolate *isolate)
    .ToLocalChecked(),
    v8::FunctionTemplate::New(isolate, Sleep));

    // Bind the global 'sleep' function to the C++ Print callback.
    global->Set(
    v8::String::NewFromUtf8(isolate, "print", v8::NewStringType::kNormal)
    .ToLocalChecked(),
    v8::FunctionTemplate::New(isolate, Print));

    return v8::Context::New(isolate, NULL, global);
    }

    // The callback that is invoked by v8 whenever the JavaScript 'print'
    // function is called. Prints its arguments on stdout separated by
    // spaces and ending with a newline.
    void Print(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    bool first = true;
    for (int i = 0; i < args.Length(); i++)
    {
    v8::HandleScope handle_scope(args.GetIsolate());
    if (first)
    {
    first = false;
    }
    else
    {
    printf(" ");
    }
    v8::String::Utf8Value str(args.GetIsolate(), args[i]);
    const char *cstr = ToCString(str);
    printf("%s", cstr);
    }
    printf("\n");
    fflush(stdout);
    }

    void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    v8::Isolate *isolate = args.GetIsolate();
    @@ -97,34 +137,39 @@ void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args)
    std::cout << "sleep 2" << std::endl;
    }

    void do_work(void *p)
    void do_work(v8::Isolate *isolate, v8::Local<v8::Context> &context,
    const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    std::cout << "do_work 0" << std::endl;
    v8::Isolate *isolate = (v8::Isolate *)p;

    v8::Locker locker(isolate);
    std::cout << "do_work 2" << std::endl;
    std::cout << "do_work 1" << std::endl;

    v8::Isolate::Scope isolate_scope(isolate);
    std::cout << "do_work 3" << std::endl;
    std::cout << "do_work 2" << std::endl;

    v8::HandleScope handle_scope(isolate);
    std::cout << "do_work 4" << std::endl;
    std::cout << "do_work 3" << std::endl;

    // v8::Context::Scope context_scope(
    // v8::Local<v8::Context>::New(isolate, isolate->GetCurrentContext()));
    // std::cout << "do_work 5" << std::endl;
    // v8::Local<v8::Context>::New(isolate, context));
    // std::cout << "do_work 4" << std::endl;

    v8::Local<v8::Function> fn = v8::Local<v8::Function>::Cast(args[0]);
    std::cout << "do_work 5" << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(2));
    v8::Local<v8::Value> v = fn->Call(v8::Undefined(isolate), 0, NULL);
    std::cout << "do_work 6" << std::endl;
    }

    void Start(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    std::cout << "Start start" << std::endl;
    v8::Local<v8::Function> fn = v8::Local<v8::Function>::Cast(args[0]);
    v8::Isolate *isolate = args.GetIsolate();

    std::thread new_thread(do_work, isolate);
    v8::Local<v8::Context> context = isolate->GetCurrentContext();

    std::thread new_thread(do_work, isolate, std::ref(context), std::ref(args));
    new_thread.detach();

    std::cout << "Start end" << std::endl;
  7. ngot revised this gist Sep 14, 2017. 1 changed file with 23 additions and 19 deletions.
    42 changes: 23 additions & 19 deletions demo.cpp
    Original file line number Diff line number Diff line change
    @@ -31,6 +31,7 @@ int main(int argc, char *argv[])
    v8::Isolate *isolate = v8::Isolate::New(create_params);

    {
    v8::Locker locker(isolate);
    v8::Isolate::Scope isolate_scope(isolate);

    // Create a stack-allocated handle scope.
    @@ -44,7 +45,7 @@ int main(int argc, char *argv[])

    // Create a string containing the JavaScript source code.
    v8::Local<v8::String> source =
    v8::String::NewFromUtf8(isolate, "start(()=>{console.log(123)});",
    v8::String::NewFromUtf8(isolate, "start();sleep(2);",
    v8::NewStringType::kNormal)
    .ToLocalChecked();

    @@ -90,24 +91,31 @@ v8::Local<v8::Context> CreateContext(v8::Isolate *isolate)

    void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    std::cout << "sleep start" << std::endl;
    v8::Isolate *isolate = args.GetIsolate();
    if (v8::Locker::IsLocked(isolate))
    v8::Unlocker unlocker(isolate);

    int time = args[0]->Int32Value(isolate->GetCurrentContext()).FromMaybe(0);
    std::this_thread::sleep_for(std::chrono::seconds(time));
    std::cout << "sleep end" << std::endl;
    std::cout << "sleep 1" << std::endl;
    v8::Unlocker unlocker(isolate);
    std::cout << "sleep 2" << std::endl;
    }

    void do_work(void *p, std::promise<void> barrier)
    void do_work(void *p)
    {
    std::cout << "do_work 0" << std::endl;
    v8::Isolate *isolate = (v8::Isolate *)p;
    // v8::Locker locker(isolate); // crash
    std::cout << "do_work start" << std::endl;
    v8::Locker locker(isolate);
    std::cout << "do_work 2" << std::endl;

    v8::Isolate::Scope isolate_scope(isolate);
    std::cout << "do_work 3" << std::endl;

    v8::HandleScope handle_scope(isolate);
    std::cout << "do_work 4" << std::endl;

    // v8::Context::Scope context_scope(
    // v8::Local<v8::Context>::New(isolate, isolate->GetCurrentContext()));
    // std::cout << "do_work 5" << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(2));
    barrier.set_value();
    std::cout << "do_work end" << std::endl;
    std::cout << "do_work 6" << std::endl;
    }

    void Start(const v8::FunctionCallbackInfo<v8::Value> &args)
    @@ -116,12 +124,8 @@ void Start(const v8::FunctionCallbackInfo<v8::Value> &args)
    v8::Local<v8::Function> fn = v8::Local<v8::Function>::Cast(args[0]);
    v8::Isolate *isolate = args.GetIsolate();

    std::promise<void> new_promise;
    std::future<void> new_future = new_promise.get_future();
    std::thread new_thread(do_work, isolate, std::move(new_promise));
    new_future.wait();
    new_future.get();
    new_thread.join();
    std::thread new_thread(do_work, isolate);
    new_thread.detach();

    std::cout << "Start end" << std::endl;
    }
  8. ngot created this gist Sep 13, 2017.
    127 changes: 127 additions & 0 deletions demo.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,127 @@
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <iostream>

    #include <chrono>
    #include <thread>
    #include <future>

    #include "libplatform/libplatform.h"
    #include "v8.h"

    v8::Local<v8::Context> CreateContext(v8::Isolate *isolate);
    void Start(const v8::FunctionCallbackInfo<v8::Value> &args);
    void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args);

    int main(int argc, char *argv[])
    {
    // Initialize V8.
    v8::V8::InitializeICUDefaultLocation(argv[0]);
    v8::V8::InitializeExternalStartupData(argv[0]);
    v8::Platform *platform = v8::platform::CreateDefaultPlatform();
    v8::V8::InitializePlatform(platform);
    v8::V8::Initialize();

    // Create a new Isolate and make it the current one.
    v8::Isolate::CreateParams create_params;
    create_params.array_buffer_allocator =
    v8::ArrayBuffer::Allocator::NewDefaultAllocator();

    v8::Isolate *isolate = v8::Isolate::New(create_params);

    {
    v8::Isolate::Scope isolate_scope(isolate);

    // Create a stack-allocated handle scope.
    v8::HandleScope handle_scope(isolate);

    // Create a new context.
    v8::Local<v8::Context> context = CreateContext(isolate);

    // Enter the context for compiling and running the hello world script.
    v8::Context::Scope context_scope(context);

    // Create a string containing the JavaScript source code.
    v8::Local<v8::String> source =
    v8::String::NewFromUtf8(isolate, "start(()=>{console.log(123)});",
    v8::NewStringType::kNormal)
    .ToLocalChecked();

    // Compile the source code.
    v8::Local<v8::Script> script =
    v8::Script::Compile(context, source).ToLocalChecked();

    // Run the script to get the result.
    v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();

    // Convert the result to an UTF8 string and print it.
    v8::String::Utf8Value utf8(isolate, result);
    printf("%s\n", *utf8);
    }

    // Dispose the isolate and tear down V8.
    isolate->Dispose();
    v8::V8::Dispose();
    v8::V8::ShutdownPlatform();
    delete platform;
    delete create_params.array_buffer_allocator;
    return 0;
    }

    v8::Local<v8::Context> CreateContext(v8::Isolate *isolate)
    {
    // Create a template for the global object.
    v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
    // Bind the global 'start' function to the C++ Print callback.
    global->Set(
    v8::String::NewFromUtf8(isolate, "start", v8::NewStringType::kNormal)
    .ToLocalChecked(),
    v8::FunctionTemplate::New(isolate, Start));

    // Bind the global 'sleep' function to the C++ Print callback.
    global->Set(
    v8::String::NewFromUtf8(isolate, "sleep", v8::NewStringType::kNormal)
    .ToLocalChecked(),
    v8::FunctionTemplate::New(isolate, Sleep));

    return v8::Context::New(isolate, NULL, global);
    }

    void Sleep(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    std::cout << "sleep start" << std::endl;
    v8::Isolate *isolate = args.GetIsolate();
    if (v8::Locker::IsLocked(isolate))
    v8::Unlocker unlocker(isolate);

    int time = args[0]->Int32Value(isolate->GetCurrentContext()).FromMaybe(0);
    std::this_thread::sleep_for(std::chrono::seconds(time));
    std::cout << "sleep end" << std::endl;
    }

    void do_work(void *p, std::promise<void> barrier)
    {
    v8::Isolate *isolate = (v8::Isolate *)p;
    // v8::Locker locker(isolate); // crash
    std::cout << "do_work start" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
    barrier.set_value();
    std::cout << "do_work end" << std::endl;
    }

    void Start(const v8::FunctionCallbackInfo<v8::Value> &args)
    {
    std::cout << "Start start" << std::endl;
    v8::Local<v8::Function> fn = v8::Local<v8::Function>::Cast(args[0]);
    v8::Isolate *isolate = args.GetIsolate();

    std::promise<void> new_promise;
    std::future<void> new_future = new_promise.get_future();
    std::thread new_thread(do_work, isolate, std::move(new_promise));
    new_future.wait();
    new_future.get();
    new_thread.join();

    std::cout << "Start end" << std::endl;
    }