* 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);
};
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.
*/
};
+//
+// 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
//
V(ScriptId) \
V(ScriptLineOffset) \
V(ScriptColumnOffset) \
+ V(ScriptData) \
V(ScriptType) \
V(ScriptLineEnds) \
V(ObjectPrototype)
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*);
}
+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 ---
}
+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,
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(
columnOffset: script.columnOffset(),
lineCount: script.lineCount(),
};
+ if (!IS_UNDEFINED(script.data())) {
+ o.data = script.data();
+ }
if (include_source) {
o.source = script.source();
}
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 {
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());
};
+ScriptMirror.prototype.data = function() {
+ return this.script_.data;
+};
+
+
ScriptMirror.prototype.scriptType = function() {
return this.script_.type;
};
VerifyPointer(name());
line_offset()->SmiVerify();
column_offset()->SmiVerify();
+ VerifyPointer(data());
+ VerifyPointer(wrapper());
type()->SmiVerify();
+ VerifyPointer(line_ends());
+ VerifyPointer(id());
}
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)
// 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)
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;
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;
}
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);
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) {"
// 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;
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);
+ }
+ }
}
}
// 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);
+}