-
-
Save msrkp/1ed54c513caef9f0e0b5cfa9b9c35cde to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //`$ clang++ hello_world.cc -I. -Iinclude -Lout.gn/discord.release/obj -lv8_monolith -o hello_world -std=c++17 -stdlib=libc++ -DV8_COMPRESS_POINTERS -target arm64-apple-macos11 -lpthread&& ./hello_world` | |
| #include <libplatform/libplatform.h> | |
| #include <v8.h> | |
| #include <iostream> | |
| namespace my_bridge { | |
| const int kMaxRecursion = 1000; | |
| bool DeepFreeze(const v8::Local<v8::Object>& object, | |
| v8::Local<v8::Context> context) { | |
| v8::Local<v8::Array> property_names = | |
| object->GetOwnPropertyNames(context).ToLocalChecked(); | |
| for (uint32_t i = 0; i < property_names->Length(); ++i) { | |
| v8::Local<v8::Value> child = | |
| object->Get(context, property_names->Get(context, i).ToLocalChecked()) | |
| .ToLocalChecked(); | |
| if (child->IsObject()) { | |
| DeepFreeze(child.As<v8::Object>(), context); | |
| } | |
| } | |
| return object->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen) | |
| .ToChecked(); | |
| } | |
| v8::MaybeLocal<v8::Value> PassValueToOtherContext( | |
| v8::Local<v8::Context> source_context, | |
| v8::Local<v8::Context> destination_context, v8::Local<v8::Value> value) { | |
| v8::Context::Scope destination_scope(destination_context); | |
| if (value->IsFunction()) { | |
| v8::Local<v8::Function> original_func = value.As<v8::Function>(); | |
| return v8::MaybeLocal<v8::Value>( | |
| v8::Function::New(destination_context, | |
| [](const v8::FunctionCallbackInfo<v8::Value>& info) { | |
| info.GetReturnValue().Set( | |
| v8::String::NewFromUtf8(info.GetIsolate(), | |
| "Proxy function called") | |
| .ToLocalChecked()); | |
| }) | |
| .ToLocalChecked()); | |
| } | |
| if (value->IsObject()) { | |
| v8::Local<v8::Object> obj = value.As<v8::Object>(); | |
| DeepFreeze(obj, destination_context); | |
| return obj; | |
| } | |
| return v8::MaybeLocal<v8::Value>(value); | |
| } | |
| void ExposeInMainWorld(v8::Isolate* isolate, | |
| v8::Local<v8::Context> main_context, | |
| v8::Local<v8::Object> object, const std::string& name) { | |
| v8::Context::Scope main_scope(main_context); | |
| main_context->Global() | |
| ->Set(main_context, | |
| v8::String::NewFromUtf8(isolate, name.c_str()).ToLocalChecked(), | |
| object) | |
| .Check(); | |
| } | |
| } // namespace my_bridge | |
| void ConsoleLog(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| if (args.Length() < 1) return; | |
| v8::String::Utf8Value str(args.GetIsolate(), args[0]); | |
| std::cout << *str << std::endl; | |
| } | |
| void SetUpConsole(v8::Isolate* isolate, v8::Local<v8::Context> context) { | |
| v8::Context::Scope context_scope(context); | |
| v8::Local<v8::Object> console = v8::Object::New(isolate); | |
| console | |
| ->Set(context, v8::String::NewFromUtf8(isolate, "log").ToLocalChecked(), | |
| v8::Function::New(context, ConsoleLog).ToLocalChecked()) | |
| .Check(); | |
| context->Global() | |
| ->Set(context, | |
| v8::String::NewFromUtf8(isolate, "console").ToLocalChecked(), | |
| console) | |
| .Check(); | |
| } | |
| void InitializeContextBridge(v8::Isolate* isolate) { | |
| v8::HandleScope handle_scope(isolate); | |
| auto main_context = v8::Context::New(isolate); // [1] | |
| SetUpConsole(isolate, main_context); | |
| v8::Global<v8::Context> main_context_global(isolate, main_context); | |
| isolate->SetData(0, &main_context_global); | |
| auto isolated_context = v8::Context::New(isolate); // [2] | |
| SetUpConsole(isolate, isolated_context); | |
| v8::Context::Scope isolated_scope(isolated_context); | |
| isolated_context->Global() | |
| ->Set(isolated_context, | |
| v8::String::NewFromUtf8(isolate, "ExposeInMainWorld") | |
| .ToLocalChecked(), | |
| v8::Function::New( | |
| isolated_context, | |
| [](const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| if (args.Length() < 2 || !args[0]->IsString() || | |
| !args[1]->IsObject()) { | |
| args.GetIsolate()->ThrowException( | |
| v8::String::NewFromUtf8(args.GetIsolate(), | |
| "Invalid arguments") | |
| .ToLocalChecked()); | |
| return; | |
| } | |
| v8::Isolate* isolate = args.GetIsolate(); | |
| v8::String::Utf8Value name(isolate, args[0]); | |
| v8::Local<v8::Object> object = args[1].As<v8::Object>(); | |
| v8::Local<v8::Context> main_context = | |
| v8::Local<v8::Context>::New( | |
| isolate, *static_cast<v8::Global<v8::Context>*>( | |
| isolate->GetData(0))); | |
| my_bridge::ExposeInMainWorld(isolate, main_context, object, | |
| *name); | |
| }) | |
| .ToLocalChecked()) | |
| .Check(); | |
| const char* isolated_code = R"( | |
| console.log("In Isolated Context:"); | |
| var regexp = /^only_allow_this_[a-z0-9_-]+$/; | |
| %DebugPrint(regexp); | |
| %DebugPrint(regexp.source); | |
| function requireModule(name) { | |
| if (regexp.test(name) ) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| const myObject = { name: "isolated_object", requireModule:requireModule} | |
| ExposeInMainWorld("exposedObject", myObject); | |
| %DebugPrint(myObject); | |
| )"; | |
| v8::Local<v8::String> source = | |
| v8::String::NewFromUtf8(isolate, isolated_code).ToLocalChecked(); | |
| v8::Local<v8::Script> script; | |
| if (!v8::Script::Compile(isolated_context, source).ToLocal(&script)) { | |
| std::cerr << "Failed to compile isolated context script." << std::endl; | |
| return; | |
| } | |
| script->Run(isolated_context).ToLocalChecked(); | |
| const char* main_code = R"( | |
| console.log("In Main Context:"); | |
| %DebugPrint(exposedObject); | |
| console.log(exposedObject.requireModule('test')); | |
| )"; | |
| v8::Local<v8::String> main_source = | |
| v8::String::NewFromUtf8(isolate, main_code).ToLocalChecked(); | |
| v8::Local<v8::Script> main_script; | |
| if (!v8::Script::Compile(main_context, main_source).ToLocal(&main_script)) { | |
| std::cerr << "Failed to compile main context script." << std::endl; | |
| return; | |
| } | |
| main_script->Run(main_context).ToLocalChecked(); | |
| } | |
| int main(int argc, char* argv[]) { | |
| // Set V8 flags to increase memory limits and allow native syntax | |
| const char* flags = | |
| "--max-old-space-size=2048 --max-semi-space-size=64 " | |
| "--allow-natives-syntax"; | |
| v8::V8::SetFlagsFromString(flags); | |
| v8::V8::SetFlagsFromString(flags); | |
| v8::V8::InitializeICUDefaultLocation(argv[0]); | |
| v8::V8::InitializeExternalStartupData(argv[0]); | |
| std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform(); | |
| v8::V8::InitializePlatform(platform.get()); | |
| v8::V8::Initialize(); | |
| 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); | |
| InitializeContextBridge(isolate); | |
| } | |
| isolate->Dispose(); | |
| v8::V8::Dispose(); | |
| v8::V8::ShutdownPlatform(); | |
| delete create_params.array_buffer_allocator; | |
| return 0; | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment