Skip to content

Commit cb5f123

Browse files
Kent Hansennierob
Kent Hansen
authored andcommitted
QtScript/V8: Add API for manipulating scope and function contexts
Needed for the implementation of QScriptEngine::{push,pop}Context(), QScriptContext::{push,pop}Scope() and friends. This API is experimental and added only for the purpose of our research. The upstream v8 API only provides access to global context objects. Internally, there are two other types of context objects: FunctionContexts, used to implement closures, and WithContexts, used to implement JS "with" statements. The API added in this change provides a way to construct and access such context objects from C++.
1 parent 1e49af8 commit cb5f123

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

src/3rdparty/v8/include/v8.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3304,6 +3304,49 @@ class V8EXPORT Context {
33043304
Handle<Context> context_;
33053305
};
33063306

3307+
#ifdef QT_BUILD_SCRIPT_LIB
3308+
/**
3309+
* Creates a new scope context.
3310+
*
3311+
* The currently entered context will be the new context's previous
3312+
* scope.
3313+
*
3314+
* Properties on the given object, scope_object, are accessible from
3315+
* the new scope.
3316+
*/
3317+
static Local<Context> NewScopeContext(Handle<Object> scope_object);
3318+
3319+
/**
3320+
* Creates a new function context.
3321+
*
3322+
* The currently entered context will be the new context's previous
3323+
* scope.
3324+
*/
3325+
static Local<Context> NewFunctionContext();
3326+
3327+
/**
3328+
* Returns the extension object of this context.
3329+
*
3330+
* For a scope context, the extension object is the object that was
3331+
* passed to NewScopeContext().
3332+
*
3333+
* For a function context, the extension object is the object that's
3334+
* used to hold the context's dynamically instantiated variables
3335+
* (e.g. by eval()).
3336+
*/
3337+
Local<Object> GetExtensionObject();
3338+
3339+
/**
3340+
* Gets the previous context.
3341+
*/
3342+
Local<Context> GetPrevious();
3343+
3344+
/**
3345+
* Gets the context corresponding to the top-most JavaScript caller.
3346+
*/
3347+
static Local<Context> GetCallerContext();
3348+
#endif
3349+
33073350
private:
33083351
friend class Value;
33093352
friend class Script;

src/3rdparty/v8/src/api.cc

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3835,6 +3835,87 @@ void Context::DetachGlobal() {
38353835
}
38363836

38373837

3838+
#ifdef QT_BUILD_SCRIPT_LIB
3839+
Local<Context> v8::Context::NewScopeContext(v8::Handle<Object> scope_object) {
3840+
i::Isolate* isolate = i::Isolate::Current();
3841+
EnsureInitializedForIsolate(isolate, "v8::Context::NewScopeContext()");
3842+
ON_BAILOUT(isolate, "v8::Context::NewScopeContext()", return Local<Context>());
3843+
LOG_API(isolate, "Context::NewScopeContext");
3844+
3845+
ENTER_V8(isolate);
3846+
i::Handle<i::JSObject> obj = Utils::OpenHandle(*scope_object);
3847+
i::Handle<i::Context> current(isolate->context());
3848+
i::Handle<i::Context> context = isolate->factory()->NewWithContext(current, obj, /*is_catch_context=*/false);
3849+
return Utils::ToLocal(context);
3850+
}
3851+
3852+
3853+
Local<Context> v8::Context::NewFunctionContext() {
3854+
i::Isolate* isolate = i::Isolate::Current();
3855+
EnsureInitializedForIsolate(isolate, "v8::Context::NewFunctionContext()");
3856+
ON_BAILOUT(isolate, "v8::Context::NewFunctionContext()", return Local<Context>());
3857+
LOG_API(isolate, "Context::NewFunctionContext");
3858+
3859+
ENTER_V8(isolate);
3860+
i::Handle<i::JSFunction> closure(isolate->global_context()->closure());
3861+
i::Handle<i::Context> context = isolate->factory()->NewFunctionContext(i::Context::MIN_CONTEXT_SLOTS,
3862+
closure);
3863+
return Utils::ToLocal(context);
3864+
}
3865+
3866+
3867+
Local<Context> v8::Context::GetPrevious() {
3868+
i::Isolate* isolate = i::Isolate::Current();
3869+
if (IsDeadCheck(isolate, "v8::Context::GetPrevious()")) return Local<Context>();
3870+
ENTER_V8(isolate);
3871+
i::Handle<i::Context> env = Utils::OpenHandle(this);
3872+
if (env->IsGlobalContext()) return Local<Context>();
3873+
i::Context* previous = 0;
3874+
if (env->is_function_context())
3875+
previous = env->closure()->context();
3876+
else
3877+
previous = env->previous();
3878+
if (!previous) return Local<Context>();
3879+
i::Handle<i::Context> previous_handle(previous);
3880+
return Utils::ToLocal(previous_handle);
3881+
}
3882+
3883+
3884+
Local<Object> v8::Context::GetExtensionObject() {
3885+
i::Isolate* isolate = i::Isolate::Current();
3886+
if (IsDeadCheck(isolate, "v8::Context::GetExtensionObject()")) return Local<Object>();
3887+
ENTER_V8(isolate);
3888+
i::Handle<i::Context> env = Utils::OpenHandle(this);
3889+
if (!env->has_extension()) {
3890+
if (env->is_function_context()) {
3891+
// Create extension object on demand.
3892+
i::Handle<i::JSObject> ext = isolate->factory()->NewJSObject(
3893+
isolate->context_extension_function());
3894+
env->set_extension(*ext);
3895+
} else {
3896+
return Local<Object>();
3897+
}
3898+
}
3899+
i::Handle<i::Object> extension_handle(env->extension());
3900+
return Local<v8::Object>(ToApi<Object>(extension_handle));
3901+
}
3902+
3903+
3904+
v8::Local<v8::Context> Context::GetCallerContext()
3905+
{
3906+
i::JavaScriptFrameIterator it;
3907+
if (it.done())
3908+
return Local<Context>();
3909+
i::JavaScriptFrame *frame = it.frame();
3910+
ASSERT(frame);
3911+
i::Context *context = (i::Context*)frame->context();
3912+
ASSERT(context);
3913+
i::Handle<i::Context> context_handle(context);
3914+
return Utils::ToLocal(context_handle);
3915+
}
3916+
#endif
3917+
3918+
38383919
void Context::ReattachGlobal(Handle<Object> global_object) {
38393920
i::Isolate* isolate = i::Isolate::Current();
38403921
if (IsDeadCheck(isolate, "v8::Context::ReattachGlobal()")) return;

0 commit comments

Comments
 (0)