Author: [email protected]
Date: Wed May 20 00:44:59 2009
New Revision: 2006
Modified:
branches/bleeding_edge/include/v8.h
branches/bleeding_edge/src/api.cc
branches/bleeding_edge/src/top.cc
branches/bleeding_edge/src/top.h
branches/bleeding_edge/test/cctest/test-api.cc
Log:
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
Modified: branches/bleeding_edge/include/v8.h
==============================================================================
--- branches/bleeding_edge/include/v8.h (original)
+++ branches/bleeding_edge/include/v8.h Wed May 20 00:44:59 2009
@@ -2251,6 +2251,13 @@
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
* another context, the security tokens must match.
*/
Modified: branches/bleeding_edge/src/api.cc
==============================================================================
--- branches/bleeding_edge/src/api.cc (original)
+++ branches/bleeding_edge/src/api.cc Wed May 20 00:44:59 2009
@@ -2612,6 +2612,13 @@
}
+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() {
if (IsDeadCheck("v8::Context::Global()")) return Local<v8::Object>();
i::Object** ctx = reinterpret_cast<i::Object**>(this);
Modified: branches/bleeding_edge/src/top.cc
==============================================================================
--- branches/bleeding_edge/src/top.cc (original)
+++ branches/bleeding_edge/src/top.cc Wed May 20 00:44:59 2009
@@ -881,6 +881,15 @@
}
+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,
JSObject* prototype,
JSFunction* function) {
Modified: branches/bleeding_edge/src/top.h
==============================================================================
--- branches/bleeding_edge/src/top.h (original)
+++ branches/bleeding_edge/src/top.h Wed May 20 00:44:59 2009
@@ -255,7 +255,12 @@
return context()->global_proxy();
}
+ // Returns the current 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() {
return Handle<JSBuiltinsObject>(thread_local_.context_->builtins());
Modified: branches/bleeding_edge/test/cctest/test-api.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-api.cc (original)
+++ branches/bleeding_edge/test/cctest/test-api.cc Wed May 20 00:44:59 2009
@@ -6608,3 +6608,67 @@
CHECK_EQ(1, force_set_set_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();
+}
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---