Commit 3cdb194c authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Add the ability to set embedder data on created contexts from the API.

Expose the active context where a break event occoured through the debug message handler.
Review URL: http://codereview.chromium.org/109013

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1857 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 74472a1b
......@@ -2259,6 +2259,14 @@ class V8EXPORT Context {
/** Returns true if V8 has a current context. */
static bool InContext();
/**
* Associate an additional data object with the context. This is mainly used
* with the debugger to provide additional information on the context through
* the debugger API.
*/
void SetData(Handle<Value> data);
Local<Value> GetData();
/**
* Stack-allocated class which sets the execution context for all
* operations executed within a local scope.
......
......@@ -445,6 +445,40 @@ void Context::Exit() {
}
void Context::SetData(v8::Handle<Value> data) {
if (IsDeadCheck("v8::Context::SetData()")) return;
ENTER_V8;
{
HandleScope scope;
i::Handle<i::Context> env = Utils::OpenHandle(this);
i::Handle<i::Object> raw_data = Utils::OpenHandle(*data);
ASSERT(env->IsGlobalContext());
if (env->IsGlobalContext()) {
env->set_data(*raw_data);
}
}
}
v8::Local<v8::Value> Context::GetData() {
if (IsDeadCheck("v8::Context::GetData()")) return v8::Local<Value>();
ENTER_V8;
i::Object* raw_result = NULL;
{
HandleScope scope;
i::Handle<i::Context> env = Utils::OpenHandle(this);
ASSERT(env->IsGlobalContext());
if (env->IsGlobalContext()) {
raw_result = env->data();
} else {
return Local<Value>();
}
}
i::Handle<i::Object> result(raw_result);
return Utils::ToLocal(result);
}
void** v8::HandleScope::RawClose(void** value) {
if (!ApiCheck(!is_closed_,
"v8::HandleScope::Close()",
......
......@@ -833,6 +833,9 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
// Initialize the out of memory slot.
global_context()->set_out_of_memory(Heap::false_value());
// Initialize the data slot.
global_context()->set_data(Heap::undefined_value());
}
......
......@@ -94,7 +94,8 @@ enum ContextLookupFlags {
V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \
V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \
V(MAP_CACHE_INDEX, Object, map_cache)
V(MAP_CACHE_INDEX, Object, map_cache) \
V(CONTEXT_DATA_INDEX, Object, data)
// JSFunctions are pairs (context, function code), sometimes also called
// closures. A Context object is used to represent function contexts and
......@@ -213,6 +214,7 @@ class Context: public FixedArray {
CONTEXT_EXTENSION_FUNCTION_INDEX,
OUT_OF_MEMORY_INDEX,
MAP_CACHE_INDEX,
CONTEXT_DATA_INDEX,
GLOBAL_CONTEXT_SLOTS
};
......
......@@ -2172,7 +2172,7 @@ v8::Handle<v8::String> MessageImpl::GetJSON() const {
v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
return v8::Handle<v8::Context>();
return v8::Utils::ToLocal(Debug::debugger_entry()->GetContext());
}
......
......@@ -687,6 +687,9 @@ class EnterDebugger BASE_EMBEDDED {
// Check whether there are any JavaScript frames on the stack.
inline bool HasJavaScriptFrames() { return has_js_frames_; }
// Get the active context from before entering the debugger.
inline Handle<Context> GetContext() { return save_.context(); }
private:
EnterDebugger* prev_; // Previous debugger entry if entered recursively.
JavaScriptFrameIterator it_;
......
......@@ -167,11 +167,22 @@ static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
(*env)->Global()->Get(v8::String::New(function_name)));
}
// Compile and run the supplied source and return the requested function.
static v8::Local<v8::Function> CompileFunction(const char* source,
const char* function_name) {
v8::Script::Compile(v8::String::New(source))->Run();
return v8::Local<v8::Function>::Cast(
v8::Context::GetCurrent()->Global()->Get(v8::String::New(function_name)));
}
// Helper function that compiles and runs the source.
static v8::Local<v8::Value> CompileRun(const char* source) {
return v8::Script::Compile(v8::String::New(source))->Run();
}
// Is there any debug info for the function?
static bool HasDebugInfo(v8::Handle<v8::Function> fun) {
Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
......@@ -4588,3 +4599,84 @@ TEST(ScriptNameAndData) {
CHECK_EQ("new name", last_script_name_hit);
CHECK_EQ("abc 123", last_script_data_hit);
}
static v8::Persistent<v8::Context> expected_context;
static v8::Handle<v8::Value> expected_context_data;
// Check that the expected context is the one generating the debug event.
static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
CHECK(message.GetEventContext() == expected_context);
CHECK(message.GetEventContext()->GetData()->StrictEquals(
expected_context_data));
message_handler_hit_count++;
const int kBufferSize = 1000;
uint16_t buffer[kBufferSize];
const char* command_continue =
"{\"seq\":0,"
"\"type\":\"request\","
"\"command\":\"continue\"}";
// Send a continue command for break events.
if (message.GetEvent() == v8::Break) {
v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
}
}
// Test which creates two contexts and sets different embedder data on each.
// Checks that this data is set correctly and that when the debug message
// handler is called the expected context is the one active.
TEST(ContextData) {
v8::HandleScope scope;
v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
// Create two contexts.
v8::Persistent<v8::Context> context_1;
v8::Persistent<v8::Context> context_2;
v8::Handle<v8::ObjectTemplate> global_template =
v8::Handle<v8::ObjectTemplate>();
v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
context_1 = v8::Context::New(NULL, global_template, global_object);
context_2 = v8::Context::New(NULL, global_template, global_object);
// Default data value is undefined.
CHECK(context_1->GetData()->IsUndefined());
CHECK(context_2->GetData()->IsUndefined());
// Set and check different data values.
v8::Handle<v8::Value> data_1 = v8::Number::New(1);
v8::Handle<v8::Value> data_2 = v8::String::New("2");
context_1->SetData(data_1);
context_2->SetData(data_2);
CHECK(context_1->GetData()->StrictEquals(data_1));
CHECK(context_2->GetData()->StrictEquals(data_2));
// Simple test function which causes a break.
char* source = "function f() { debugger; }";
// Enter and run function in the first context.
{
v8::Context::Scope context_scope(context_1);
expected_context = context_1;
expected_context_data = data_1;
v8::Local<v8::Function> f = CompileFunction(source, "f");
f->Call(context_1->Global(), 0, NULL);
}
// Enter and run function in the second context.
{
v8::Context::Scope context_scope(context_2);
expected_context = context_2;
expected_context_data = data_2;
v8::Local<v8::Function> f = CompileFunction(source, "f");
f->Call(context_2->Global(), 0, NULL);
}
// Two times compile event and two times break event.
CHECK_GT(message_handler_hit_count, 4);
}
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