Commit 10b8928e authored by ager@chromium.org's avatar ager@chromium.org

Expose the calling context through the API.

In C++ callbacks, we can now get the context of the javascript code
that called the callback.

Review URL: http://codereview.chromium.org/113622

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2006 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 897ecefe
...@@ -2250,6 +2250,13 @@ class V8EXPORT Context { ...@@ -2250,6 +2250,13 @@ class V8EXPORT Context {
/** Returns the context that is on the top of the stack. */ /** Returns the context that is on the top of the stack. */
static Local<Context> GetCurrent(); static Local<Context> GetCurrent();
/**
* Returns the context of the calling JavaScript code. That is the
* context of the top-most JavaScript frame. If there are no
* JavaScript frames an empty handle is returned.
*/
static Local<Context> GetCalling();
/** /**
* Sets the security token for the context. To access an object in * Sets the security token for the context. To access an object in
* another context, the security tokens must match. * another context, the security tokens must match.
......
...@@ -2612,6 +2612,13 @@ v8::Local<v8::Context> Context::GetCurrent() { ...@@ -2612,6 +2612,13 @@ v8::Local<v8::Context> Context::GetCurrent() {
} }
v8::Local<v8::Context> Context::GetCalling() {
if (IsDeadCheck("v8::Context::GetCalling()")) return Local<Context>();
i::Handle<i::Context> context(i::Top::GetCallingGlobalContext());
return Utils::ToLocal(context);
}
v8::Local<v8::Object> Context::Global() { v8::Local<v8::Object> Context::Global() {
if (IsDeadCheck("v8::Context::Global()")) return Local<v8::Object>(); if (IsDeadCheck("v8::Context::Global()")) return Local<v8::Object>();
i::Object** ctx = reinterpret_cast<i::Object**>(this); i::Object** ctx = reinterpret_cast<i::Object**>(this);
......
...@@ -881,6 +881,15 @@ Handle<Context> Top::global_context() { ...@@ -881,6 +881,15 @@ Handle<Context> Top::global_context() {
} }
Handle<Context> Top::GetCallingGlobalContext() {
JavaScriptFrameIterator it;
if (it.done()) return Handle<Context>::null();
JavaScriptFrame* frame = it.frame();
Context* context = Context::cast(frame->context());
return Handle<Context>(context->global_context());
}
Object* Top::LookupSpecialFunction(JSObject* receiver, Object* Top::LookupSpecialFunction(JSObject* receiver,
JSObject* prototype, JSObject* prototype,
JSFunction* function) { JSFunction* function) {
......
...@@ -255,8 +255,13 @@ class Top { ...@@ -255,8 +255,13 @@ class Top {
return context()->global_proxy(); return context()->global_proxy();
} }
// Returns the current global context.
static Handle<Context> global_context(); static Handle<Context> global_context();
// Returns the global context of the calling JavaScript code. That
// is, the global context of the top-most JavaScript frame.
static Handle<Context> GetCallingGlobalContext();
static Handle<JSBuiltinsObject> builtins() { static Handle<JSBuiltinsObject> builtins() {
return Handle<JSBuiltinsObject>(thread_local_.context_->builtins()); return Handle<JSBuiltinsObject>(thread_local_.context_->builtins());
} }
......
...@@ -6608,3 +6608,67 @@ TEST(ForceSetWithInterceptor) { ...@@ -6608,3 +6608,67 @@ TEST(ForceSetWithInterceptor) {
CHECK_EQ(1, force_set_set_count); CHECK_EQ(1, force_set_set_count);
CHECK_EQ(6, force_set_get_count); CHECK_EQ(6, force_set_get_count);
} }
v8::Persistent<Context> calling_context0;
v8::Persistent<Context> calling_context1;
v8::Persistent<Context> calling_context2;
// Check that the call to the callback is initiated in
// calling_context2, the directly calling context is calling_context1
// and the callback itself is in calling_context0.
static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
CHECK(Context::GetCurrent() == calling_context0);
CHECK(Context::GetCalling() == calling_context1);
CHECK(Context::GetEntered() == calling_context2);
return v8::Integer::New(42);
}
THREADED_TEST(GetCallingContext) {
v8::HandleScope scope;
calling_context0 = Context::New();
calling_context1 = Context::New();
calling_context2 = Context::New();
// Allow cross-domain access.
Local<String> token = v8_str("<security token>");
calling_context0->SetSecurityToken(token);
calling_context1->SetSecurityToken(token);
calling_context2->SetSecurityToken(token);
// Create an object with a C++ callback in context0.
calling_context0->Enter();
Local<v8::FunctionTemplate> callback_templ =
v8::FunctionTemplate::New(GetCallingContextCallback);
calling_context0->Global()->Set(v8_str("callback"),
callback_templ->GetFunction());
calling_context0->Exit();
// Expose context0 in context1 and setup a function that calls the
// callback function.
calling_context1->Enter();
calling_context1->Global()->Set(v8_str("context0"),
calling_context0->Global());
CompileRun("function f() { context0.callback() }");
calling_context1->Exit();
// Expose context1 in context2 and call the callback function in
// context0 indirectly through f in context1.
calling_context2->Enter();
calling_context2->Global()->Set(v8_str("context1"),
calling_context1->Global());
CompileRun("context1.f()");
calling_context2->Exit();
// Dispose the contexts to allow them to be garbage collected.
calling_context0.Dispose();
calling_context1.Dispose();
calling_context2.Dispose();
calling_context0.Clear();
calling_context1.Clear();
calling_context2.Clear();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment