Commit b8dc312b authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Make it possible to add a user data object to each script compiled.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1748 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 19c95ff3
......@@ -529,6 +529,13 @@ class V8EXPORT Script {
* Returns the script id value.
*/
Local<Value> Id();
/**
* Associate an additional data object with the script. This is mainly used
* with the debugger as this data object is only available through the
* debugger API.
*/
void SetData(Handle<Value> data);
};
......@@ -540,8 +547,18 @@ class V8EXPORT Message {
Local<String> Get() const;
Local<String> GetSourceLine() const;
/**
* Returns the resource name for the script from where the function causing
* the error originates.
*/
Handle<Value> GetScriptResourceName() const;
/**
* Returns the resource data for the script from where the function causing
* the error originates.
*/
Handle<Value> GetScriptData() const;
/**
* Returns the number, 1-based, of the line where the error occurred.
*/
......
......@@ -251,6 +251,24 @@ const AccessorDescriptor Accessors::ScriptColumnOffset = {
};
//
// Accessors::ScriptData
//
Object* Accessors::ScriptGetData(Object* object, void*) {
Object* script = JSValue::cast(object)->value();
return Script::cast(script)->data();
}
const AccessorDescriptor Accessors::ScriptData = {
ScriptGetData,
IllegalSetter,
0
};
//
// Accessors::ScriptType
//
......
......@@ -45,6 +45,7 @@ namespace v8 { namespace internal {
V(ScriptId) \
V(ScriptLineOffset) \
V(ScriptColumnOffset) \
V(ScriptData) \
V(ScriptType) \
V(ScriptLineEnds) \
V(ObjectPrototype)
......@@ -84,6 +85,7 @@ class Accessors : public AllStatic {
static Object* ScriptGetSource(Object* object, void*);
static Object* ScriptGetLineOffset(Object* object, void*);
static Object* ScriptGetColumnOffset(Object* object, void*);
static Object* ScriptGetData(Object* object, void*);
static Object* ScriptGetType(Object* object, void*);
static Object* ScriptGetLineEnds(Object* object, void*);
static Object* ObjectGetPrototype(Object* receiver, void*);
......
......@@ -1108,6 +1108,19 @@ Local<Value> Script::Id() {
}
void Script::SetData(v8::Handle<Value> data) {
ON_BAILOUT("v8::Script::SetData()", return);
LOG_API("Script::SetData");
{
HandleScope scope;
i::Handle<i::JSFunction> fun = Utils::OpenHandle(this);
i::Handle<i::Object> raw_data = Utils::OpenHandle(*data);
i::Handle<i::Script> script(i::Script::cast(fun->shared()->script()));
script->set_data(*raw_data);
}
}
// --- E x c e p t i o n s ---
......@@ -1199,6 +1212,22 @@ v8::Handle<Value> Message::GetScriptResourceName() const {
}
v8::Handle<Value> Message::GetScriptData() const {
if (IsDeadCheck("v8::Message::GetScriptResourceData()")) {
return Local<Value>();
}
ENTER_V8;
HandleScope scope;
i::Handle<i::JSObject> obj =
i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
// Return this.script.data.
i::Handle<i::JSValue> script =
i::Handle<i::JSValue>::cast(GetProperty(obj, "script"));
i::Handle<i::Object> data(i::Script::cast(script->value())->data());
return scope.Close(Utils::ToLocal(data));
}
static i::Handle<i::Object> CallV8HeapFunction(const char* name,
i::Handle<i::Object> recv,
int argc,
......
......@@ -1019,6 +1019,13 @@ bool Genesis::InstallNatives() {
Factory::LookupAsciiSymbol("column_offset"),
proxy_column_offset,
common_attributes);
Handle<Proxy> proxy_data = Factory::NewProxy(&Accessors::ScriptData);
script_descriptors =
Factory::CopyAppendProxyDescriptor(
script_descriptors,
Factory::LookupAsciiSymbol("data"),
proxy_data,
common_attributes);
Handle<Proxy> proxy_type = Factory::NewProxy(&Accessors::ScriptType);
script_descriptors =
Factory::CopyAppendProxyDescriptor(
......
......@@ -1021,6 +1021,9 @@ function MakeScriptObject_(script, include_source) {
columnOffset: script.columnOffset(),
lineCount: script.lineCount(),
};
if (!IS_UNDEFINED(script.data())) {
o.data = script.data();
}
if (include_source) {
o.source = script.source();
}
......@@ -1679,6 +1682,9 @@ DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
script.lineOffset = scripts[i].line_offset;
script.columnOffset = scripts[i].column_offset;
script.lineCount = scripts[i].lineCount();
if (scripts[i].data) {
script.data = scripts[i].data;
}
if (includeSource) {
script.source = scripts[i].source;
} else {
......
......@@ -173,6 +173,7 @@ Handle<Script> Factory::NewScript(Handle<String> source) {
script->set_id(Heap::last_script_id());
script->set_line_offset(Smi::FromInt(0));
script->set_column_offset(Smi::FromInt(0));
script->set_data(Heap::undefined_value());
script->set_type(Smi::FromInt(SCRIPT_TYPE_NORMAL));
script->set_wrapper(*Factory::NewProxy(0, TENURED));
script->set_line_ends(Heap::undefined_value());
......
......@@ -1582,6 +1582,11 @@ ScriptMirror.prototype.columnOffset = function() {
};
ScriptMirror.prototype.data = function() {
return this.script_.data;
};
ScriptMirror.prototype.scriptType = function() {
return this.script_.type;
};
......
......@@ -924,7 +924,11 @@ void Script::ScriptVerify() {
VerifyPointer(name());
line_offset()->SmiVerify();
column_offset()->SmiVerify();
VerifyPointer(data());
VerifyPointer(wrapper());
type()->SmiVerify();
VerifyPointer(line_ends());
VerifyPointer(id());
}
......
......@@ -2053,6 +2053,7 @@ ACCESSORS(Script, name, Object, kNameOffset)
ACCESSORS(Script, id, Object, kIdOffset)
ACCESSORS(Script, line_offset, Smi, kLineOffsetOffset)
ACCESSORS(Script, column_offset, Smi, kColumnOffsetOffset)
ACCESSORS(Script, data, Object, kDataOffset)
ACCESSORS(Script, wrapper, Proxy, kWrapperOffset)
ACCESSORS(Script, type, Smi, kTypeOffset)
ACCESSORS(Script, line_ends, Object, kLineEndsOffset)
......
......@@ -2603,6 +2603,9 @@ class Script: public Struct {
// extracted.
DECL_ACCESSORS(column_offset, Smi)
// [data]: additional data associated with this script.
DECL_ACCESSORS(data, Object)
// [wrapper]: the wrapper cache.
DECL_ACCESSORS(wrapper, Proxy)
......@@ -2623,7 +2626,8 @@ class Script: public Struct {
static const int kNameOffset = kSourceOffset + kPointerSize;
static const int kLineOffsetOffset = kNameOffset + kPointerSize;
static const int kColumnOffsetOffset = kLineOffsetOffset + kPointerSize;
static const int kWrapperOffset = kColumnOffsetOffset + kPointerSize;
static const int kDataOffset = kColumnOffsetOffset + kPointerSize;
static const int kWrapperOffset = kDataOffset + kPointerSize;
static const int kTypeOffset = kWrapperOffset + kPointerSize;
static const int kLineEndsOffset = kTypeOffset + kPointerSize;
static const int kIdOffset = kLineEndsOffset + kPointerSize;
......
......@@ -1394,6 +1394,7 @@ static void check_message(v8::Handle<v8::Message> message,
v8::Handle<Value> data) {
CHECK_EQ(5.76, data->NumberValue());
CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
message_received = true;
}
......@@ -1406,7 +1407,10 @@ THREADED_TEST(MessageHandlerData) {
LocalContext context;
v8::ScriptOrigin origin =
v8::ScriptOrigin(v8_str("6.75"));
Script::Compile(v8_str("throw 'error'"), &origin)->Run();
v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
&origin);
script->SetData(v8_str("7.56"));
script->Run();
CHECK(message_received);
// clear out the message listener
v8::V8::RemoveMessageListeners(check_message);
......
......@@ -525,6 +525,24 @@ const char* frame_source_column_source =
v8::Local<v8::Function> frame_source_column;
// Source for The JavaScript function which picks out the script name for the
// top frame.
const char* frame_script_name_source =
"function frame_script_name(exec_state) {"
" return exec_state.frame(0).func().script().name();"
"}";
v8::Local<v8::Function> frame_script_name;
// Source for The JavaScript function which picks out the script data for the
// top frame.
const char* frame_script_data_source =
"function frame_script_data(exec_state) {"
" return exec_state.frame(0).func().script().data();"
"}";
v8::Local<v8::Function> frame_script_data;
// Source for The JavaScript function which returns the number of frames.
static const char* frame_count_source =
"function frame_count(exec_state) {"
......@@ -536,6 +554,11 @@ v8::Handle<v8::Function> frame_count;
// Global variable to store the last function hit - used by some tests.
char last_function_hit[80];
// Global variable to store the name and data for last script hit - used by some
// tests.
char last_script_name_hit[80];
char last_script_data_hit[80];
// Global variables to store the last source position - used by some tests.
int last_source_line = -1;
int last_source_column = -1;
......@@ -586,6 +609,37 @@ static void DebugEventBreakPointHitCount(v8::DebugEvent event,
CHECK(result->IsNumber());
last_source_column = result->Int32Value();
}
if (!frame_script_name.IsEmpty()) {
// Get the script name of the function script.
const int argc = 1;
v8::Handle<v8::Value> argv[argc] = { exec_state };
v8::Handle<v8::Value> result = frame_script_name->Call(exec_state,
argc, argv);
if (result->IsUndefined()) {
last_script_name_hit[0] = '\0';
} else {
CHECK(result->IsString());
v8::Handle<v8::String> script_name(result->ToString());
script_name->WriteAscii(last_script_name_hit);
}
}
if (!frame_script_data.IsEmpty()) {
// Get the script data of the function script.
const int argc = 1;
v8::Handle<v8::Value> argv[argc] = { exec_state };
v8::Handle<v8::Value> result = frame_script_data->Call(exec_state,
argc, argv);
if (result->IsUndefined()) {
last_script_data_hit[0] = '\0';
} else {
result = result->ToString();
CHECK(result->IsString());
v8::Handle<v8::String> script_data(result->ToString());
script_data->WriteAscii(last_script_data_hit);
}
}
}
}
......@@ -4249,3 +4303,58 @@ TEST(DebugGetLoadedScripts) {
// Must not crash while accessing line_ends.
i::FLAG_allow_natives_syntax = allow_natives_syntax;
}
// Test script break points set on lines.
TEST(ScriptNameAndData) {
v8::HandleScope scope;
DebugLocalContext env;
env.ExposeDebug();
// Create functions for retrieving script name and data for the function on
// the top frame when hitting a break point.
frame_script_name = CompileFunction(&env,
frame_script_name_source,
"frame_script_name");
frame_script_data = CompileFunction(&env,
frame_script_data_source,
"frame_script_data");
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined());
// Test function source.
v8::Local<v8::String> script = v8::String::New(
"function f() {\n"
" debugger;\n"
"}\n");
v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8::String::New("name"));
v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1);
script1->SetData(v8::String::New("data"));
script1->Run();
v8::Script::Compile(script, &origin1)->Run();
v8::Local<v8::Function> f;
f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
f->Call(env->Global(), 0, NULL);
CHECK_EQ(1, break_point_hit_count);
CHECK_EQ("name", last_script_name_hit);
CHECK_EQ("data", last_script_data_hit);
v8::Local<v8::String> data_obj_source = v8::String::New(
"({ a: 'abc',\n"
" b: 123,\n"
" toString: function() { return this.a + ' ' + this.b; }\n"
"})\n");
v8::Local<v8::Value> data_obj = v8::Script::Compile(data_obj_source)->Run();
v8::ScriptOrigin origin2 = v8::ScriptOrigin(v8::String::New("new name"));
v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
script2->Run();
script2->SetData(data_obj);
f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
f->Call(env->Global(), 0, NULL);
CHECK_EQ(2, break_point_hit_count);
CHECK_EQ("new name", last_script_name_hit);
CHECK_EQ("abc 123", last_script_data_hit);
}
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