diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..3f19e616 --- /dev/null +++ b/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: Chromium diff --git a/context-macros.h b/context-macros.h new file mode 100644 index 00000000..7d75d308 --- /dev/null +++ b/context-macros.h @@ -0,0 +1,20 @@ +#ifndef V8GO_CONTEXT_MACROS_H +#define V8GO_CONTEXT_MACROS_H + +#include "deps/include/v8-context.h" +#include "deps/include/v8-isolate.h" +#include "deps/include/v8-local-handle.h" +#include "deps/include/v8-locker.h" + +#include "context.h" + +#define LOCAL_CONTEXT(ctx) \ + v8::Isolate* iso = ctx->iso; \ + v8::Locker locker(iso); \ + v8::Isolate::Scope isolate_scope(iso); \ + v8::HandleScope handle_scope(iso); \ + v8::TryCatch try_catch(iso); \ + v8::Local local_ctx = ctx->ptr.Get(iso); \ + v8::Context::Scope context_scope(local_ctx); + +#endif diff --git a/context.cc b/context.cc new file mode 100644 index 00000000..ccaaf2d8 --- /dev/null +++ b/context.cc @@ -0,0 +1,121 @@ +#include "deps/include/v8-template.h" + +#include "context-macros.h" +#include "template.h" +#include "unbound_script.h" +#include "value.h" + +using namespace v8; + +ContextPtr NewContext(IsolatePtr iso, + TemplatePtr global_template_ptr, + int ref) { + Locker locker(iso); + Isolate::Scope isolate_scope(iso); + HandleScope handle_scope(iso); + + Local global_template; + if (global_template_ptr != nullptr) { + global_template = global_template_ptr->ptr.Get(iso).As(); + } else { + global_template = ObjectTemplate::New(iso); + } + + // For function callbacks we need a reference to the context, but because of + // the complexities of C -> Go function pointers, we store a reference to the + // context as a simple integer identifier; this can then be used on the Go + // side to lookup the context in the context registry. We use slot 1 as slot 0 + // has special meaning for the Chrome debugger. + Local local_ctx = Context::New(iso, nullptr, global_template); + local_ctx->SetEmbedderData(1, Integer::New(iso, ref)); + + m_ctx* ctx = new m_ctx; + ctx->ptr.Reset(iso, local_ctx); + ctx->iso = iso; + return ctx; +} + +void ContextFree(ContextPtr ctx) { + if (ctx == nullptr) { + return; + } + ctx->ptr.Reset(); + + for (auto it = ctx->vals.begin(); it != ctx->vals.end(); ++it) { + auto value = it->second; + value->ptr.Reset(); + delete value; + } + ctx->vals.clear(); + + for (m_unboundScript* us : ctx->unboundScripts) { + us->ptr.Reset(); + delete us; + } + + delete ctx; +} + +m_value* tracked_value(m_ctx* ctx, m_value* val) { + // (rogchap) we track values against a context so that when the context is + // closed (either manually or GC'd by Go) we can also release all the + // values associated with the context; + if (val->id == 0) { + val->id = ++ctx->nextValId; + ctx->vals[val->id] = val; + } + + return val; +} + +ValuePtr ContextGlobal(ContextPtr ctx) { + LOCAL_CONTEXT(ctx); + m_value* val = new m_value; + val->id = 0; + + val->iso = iso; + val->ctx = ctx; + val->ptr = Global(iso, local_ctx->Global()); + + return tracked_value(ctx, val); +} + +int ContextRetainedValueCount(ContextPtr ctx) { + return ctx->vals.size(); +} + +RtnValue RunScript(ContextPtr ctx, const char* source, const char* origin) { + LOCAL_CONTEXT(ctx); + + RtnValue rtn = {}; + + MaybeLocal maybeSrc = + String::NewFromUtf8(iso, source, NewStringType::kNormal); + MaybeLocal maybeOgn = + String::NewFromUtf8(iso, origin, NewStringType::kNormal); + Local src, ogn; + if (!maybeSrc.ToLocal(&src) || !maybeOgn.ToLocal(&ogn)) { + rtn.error = ExceptionError(try_catch, iso, local_ctx); + return rtn; + } + + ScriptOrigin script_origin(ogn); + Local