* \param pre_data Pre-parsing data, as obtained by ScriptData::PreCompile()
* using pre_data speeds compilation if it's done multiple times.
* Owned by caller, no references are kept when New() returns.
+ * \param script_data Arbitrary data associated with script. Using
+ * this has same effect as calling SetData(), but allows data to be
+ * available to compile event handlers.
* \return Compiled script object (context independent; when run it
* will use the currently entered context).
*/
static Local<Script> New(Handle<String> source,
ScriptOrigin* origin = NULL,
- ScriptData* pre_data = NULL);
+ ScriptData* pre_data = NULL,
+ Handle<String> script_data = Handle<String>());
/**
* Compiles the specified script using the specified file name
* \param pre_data Pre-parsing data, as obtained by ScriptData::PreCompile()
* using pre_data speeds compilation if it's done multiple times.
* Owned by caller, no references are kept when Compile() returns.
+ * \param script_data Arbitrary data associated with script. Using
+ * this has same effect as calling SetData(), but makes data available
+ * earlier (i.e. to compile event handlers).
* \return Compiled script object, bound to the context that was active
* when this function was called. When run it will always use this
* context.
*/
static Local<Script> Compile(Handle<String> source,
ScriptOrigin* origin = NULL,
- ScriptData* pre_data = NULL);
+ ScriptData* pre_data = NULL,
+ Handle<String> script_data = Handle<String>());
/**
* Compiles the specified script using the specified file name
*
* \param source Script source code.
* \param file_name File name to use as script's origin
+ * \param script_data Arbitrary data associated with script. Using
+ * this has same effect as calling SetData(), but makes data available
+ * earlier (i.e. to compile event handlers).
* \return Compiled script object, bound to the context that was active
* when this function was called. When run it will always use this
* context.
*/
static Local<Script> Compile(Handle<String> source,
- Handle<Value> file_name);
+ Handle<Value> file_name,
+ Handle<String> script_data = Handle<String>());
/**
* Runs the script returning the resulting value. If the script is
int GetId();
/**
+ * 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<String> data);
+
+ /**
* Returns the name value of one Script.
*/
Handle<Value> GetScriptName();
//
+// Accessors::ScriptData
+//
+
+
+MaybeObject* Accessors::ScriptGetData(Isolate* isolate,
+ 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(ScriptCompilationType) \
V(ScriptLineEnds) \
static MaybeObject* ScriptGetColumnOffset(Isolate* isolate,
Object* object,
void*);
+ static MaybeObject* ScriptGetData(Isolate* isolate, Object* object, void*);
static MaybeObject* ScriptGetType(Isolate* isolate, Object* object, void*);
static MaybeObject* ScriptGetCompilationType(Isolate* isolate,
Object* object,
Local<Script> Script::New(v8::Handle<String> source,
v8::ScriptOrigin* origin,
- v8::ScriptData* pre_data) {
+ v8::ScriptData* pre_data,
+ v8::Handle<String> script_data) {
i::Handle<i::String> str = Utils::OpenHandle(*source);
i::Isolate* isolate = str->GetIsolate();
ON_BAILOUT(isolate, "v8::Script::New()", return Local<Script>());
isolate->global_context(),
NULL,
pre_data_impl,
+ Utils::OpenHandle(*script_data, true),
i::NOT_NATIVES_CODE);
has_pending_exception = result.is_null();
EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
Local<Script> Script::Compile(v8::Handle<String> source,
v8::ScriptOrigin* origin,
- v8::ScriptData* pre_data) {
+ v8::ScriptData* pre_data,
+ v8::Handle<String> script_data) {
i::Handle<i::String> str = Utils::OpenHandle(*source);
i::Isolate* isolate = str->GetIsolate();
ON_BAILOUT(isolate, "v8::Script::Compile()", return Local<Script>());
LOG_API(isolate, "Script::Compile");
ENTER_V8(isolate);
- Local<Script> generic = New(source, origin, pre_data);
+ Local<Script> generic = New(source, origin, pre_data, script_data);
if (generic.IsEmpty())
return generic;
i::Handle<i::Object> obj = Utils::OpenHandle(*generic);
Local<Script> Script::Compile(v8::Handle<String> source,
- v8::Handle<Value> file_name) {
+ v8::Handle<Value> file_name,
+ v8::Handle<String> script_data) {
ScriptOrigin origin(file_name);
- return Compile(source, &origin);
+ return Compile(source, &origin, 0, script_data);
}
}
+void Script::SetData(v8::Handle<String> data) {
+ i::Handle<i::HeapObject> obj =
+ i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
+ i::Isolate* isolate = obj->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Script::SetData()", return);
+ LOG_API(isolate, "Script::SetData");
+ {
+ i::HandleScope scope(isolate);
+ i::Handle<i::SharedFunctionInfo> function_info = OpenScript(this);
+ i::Handle<i::Object> raw_data = Utils::OpenHandle(*data);
+ i::Handle<i::Script> script(i::Script::cast(function_info->script()));
+ script->set_data(*raw_data);
+ }
+}
+
+
// --- E x c e p t i o n s ---
}
+v8::Handle<Value> Message::GetScriptData() const {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ENTER_V8(isolate);
+ EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
+ i::Handle<i::JSMessageObject> message =
+ i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
+ // Return this.script.data.
+ i::Handle<i::JSValue> script =
+ i::Handle<i::JSValue>::cast(i::Handle<i::Object>(message->script(),
+ isolate));
+ i::Handle<i::Object> data(i::Script::cast(script->value())->data(), isolate);
+ return scope.Escape(Utils::ToLocal(data));
+}
+
+
v8::Handle<v8::StackTrace> Message::GetStackTrace() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
top_context,
extension,
NULL,
+ Handle<String>::null(),
use_runtime_context ? NATIVES_CODE : NOT_NATIVES_CODE);
if (function_info.is_null()) return false;
if (cache != NULL) cache->Add(name, function_info);
factory()->NewForeign(&Accessors::ScriptColumnOffset));
Handle<String> data_string(factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("data")));
+ Handle<Foreign> script_data(factory()->NewForeign(&Accessors::ScriptData));
Handle<String> type_string(factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("type")));
Handle<Foreign> script_type(factory()->NewForeign(&Accessors::ScriptType));
}
{
+ CallbacksDescriptor d(*data_string, *script_data, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
CallbacksDescriptor d(*type_string, *script_type, attribs);
script_map->AppendDescriptor(&d, witness);
}
Handle<Context> context,
v8::Extension* extension,
ScriptDataImpl* pre_data,
+ Handle<Object> script_data,
NativesFlag natives) {
Isolate* isolate = source->GetIsolate();
int source_length = source->length();
}
script->set_is_shared_cross_origin(is_shared_cross_origin);
+ script->set_data(script_data.is_null() ? isolate->heap()->undefined_value()
+ : *script_data);
+
// Compile the function and add it to the cache.
CompilationInfoWithZone info(script);
info.MarkAsGlobal();
Handle<Context> context,
v8::Extension* extension,
ScriptDataImpl* pre_data,
+ Handle<Object> script_data,
NativesFlag is_natives_code);
// Create a shared function info object (the code may be lazily compiled).
false,
context,
NULL, NULL,
+ Handle<String>::null(),
NATIVES_CODE);
// Silently ignore stack overflows during compilation.
script->set_id(Smi::FromInt(id));
script->set_line_offset(Smi::FromInt(0));
script->set_column_offset(Smi::FromInt(0));
+ script->set_data(heap->undefined_value());
script->set_context_data(heap->undefined_value());
script->set_type(Smi::FromInt(Script::TYPE_NORMAL));
script->set_wrapper(*wrapper);
"name", script->name(),
Script::kNameOffset);
SetInternalReference(obj, entry,
+ "data", script->data(),
+ Script::kDataOffset);
+ SetInternalReference(obj, entry,
"context_data", script->context_data(),
Script::kContextOffset);
TagObject(script->line_ends(), "(script line ends)");
copy->set_name(original->name());
copy->set_line_offset(original->line_offset());
copy->set_column_offset(original->column_offset());
+ copy->set_data(original->data());
copy->set_type(original->type());
copy->set_context_data(original->context_data());
copy->set_eval_from_shared(original->eval_from_shared());
VerifyPointer(name());
line_offset()->SmiVerify();
column_offset()->SmiVerify();
+ VerifyPointer(data());
VerifyPointer(wrapper());
type()->SmiVerify();
VerifyPointer(line_ends());
ACCESSORS(Script, id, Smi, kIdOffset)
ACCESSORS_TO_SMI(Script, line_offset, kLineOffsetOffset)
ACCESSORS_TO_SMI(Script, column_offset, kColumnOffsetOffset)
+ACCESSORS(Script, data, Object, kDataOffset)
ACCESSORS(Script, context_data, Object, kContextOffset)
ACCESSORS(Script, wrapper, Foreign, kWrapperOffset)
ACCESSORS_TO_SMI(Script, type, kTypeOffset)
type()->ShortPrint(out);
PrintF(out, "\n - id: ");
id()->ShortPrint(out);
+ PrintF(out, "\n - data: ");
+ data()->ShortPrint(out);
PrintF(out, "\n - context data: ");
context_data()->ShortPrint(out);
PrintF(out, "\n - wrapper: ");
// extracted.
DECL_ACCESSORS(column_offset, Smi)
+ // [data]: additional data associated with this script.
+ DECL_ACCESSORS(data, Object)
+
// [context_data]: context data for the context this script was compiled in.
DECL_ACCESSORS(context_data, Object)
static const int kNameOffset = kSourceOffset + kPointerSize;
static const int kLineOffsetOffset = kNameOffset + kPointerSize;
static const int kColumnOffsetOffset = kLineOffsetOffset + kPointerSize;
- static const int kContextOffset = kColumnOffsetOffset + kPointerSize;
+ static const int kDataOffset = kColumnOffsetOffset + kPointerSize;
+ static const int kContextOffset = kDataOffset + kPointerSize;
static const int kWrapperOffset = kContextOffset + kPointerSize;
static const int kTypeOffset = kWrapperOffset + kPointerSize;
static const int kLineEndsOffset = kTypeOffset + 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());
CHECK(!message->IsSharedCrossOrigin());
message_received = true;
}
v8::ScriptOrigin(v8_str("6.75"));
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
false,
Handle<Context>(isolate->native_context()),
NULL, NULL,
+ Handle<String>::null(),
NOT_NATIVES_CODE);
return isolate->factory()->NewFunctionFromSharedFunctionInfo(
shared_function, isolate->native_context());
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 picks out the script data from
+// AfterCompile event
+const char* compiled_script_data_source =
+ "function compiled_script_data(event_data) {"
+ " return event_data.script().data();"
+ "}";
+v8::Local<v8::Function> compiled_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 for last script hit - used by some tests.
+// 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;
const v8::Debug::EventDetails& event_details) {
v8::DebugEvent event = event_details.GetEvent();
v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
+ v8::Handle<v8::Object> event_data = event_details.GetEventData();
v8::internal::Isolate* isolate = CcTest::i_isolate();
Debug* debug = isolate->debug();
// When hitting a debug event listener there must be a break set.
}
}
+ 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->WriteUtf8(last_script_data_hit);
+ }
+ }
+
// Perform a full deoptimization when the specified number of
// breaks have been hit.
if (break_point_hit_count == break_point_hit_count_deoptimize) {
i::Deoptimizer::DeoptimizeAll(isolate);
}
+ } else if (event == v8::AfterCompile && !compiled_script_data.IsEmpty()) {
+ const int argc = 1;
+ v8::Handle<v8::Value> argv[argc] = { event_data };
+ v8::Handle<v8::Value> result = compiled_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->WriteUtf8(last_script_data_hit);
+ }
}
}
frame_script_name = CompileFunction(&env,
frame_script_name_source,
"frame_script_name");
+ frame_script_data = CompileFunction(&env,
+ frame_script_data_source,
+ "frame_script_data");
+ compiled_script_data = CompileFunction(&env,
+ compiled_script_data_source,
+ "compiled_script_data");
v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount);
v8::ScriptOrigin origin1 =
v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "name"));
v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1);
+ script1->SetData(v8::String::NewFromUtf8(env->GetIsolate(), "data"));
script1->Run();
v8::Local<v8::Function> f;
f = v8::Local<v8::Function>::Cast(
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);
// Compile the same script again without setting data. As the compilation
// cache is disabled when debugging expect the data to be missing.
f->Call(env->Global(), 0, NULL);
CHECK_EQ(2, break_point_hit_count);
CHECK_EQ("name", last_script_name_hit);
+ CHECK_EQ("", last_script_data_hit); // Undefined results in empty string.
v8::Local<v8::String> data_obj_source = v8::String::NewFromUtf8(
env->GetIsolate(),
" b: 123,\n"
" toString: function() { return this.a + ' ' + this.b; }\n"
"})\n");
- v8::Script::Compile(data_obj_source)->Run();
+ v8::Local<v8::Value> data_obj = v8::Script::Compile(data_obj_source)->Run();
v8::ScriptOrigin origin2 =
v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "new name"));
v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
script2->Run();
+ script2->SetData(data_obj->ToString());
f = v8::Local<v8::Function>::Cast(
env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
f->Call(env->Global(), 0, NULL);
CHECK_EQ(3, break_point_hit_count);
CHECK_EQ("new name", last_script_name_hit);
+ CHECK_EQ("abc 123", last_script_data_hit);
v8::Handle<v8::Script> script3 = v8::Script::Compile(
- script, &origin2, NULL);
+ script, &origin2, NULL,
+ v8::String::NewFromUtf8(env->GetIsolate(), "in compile"));
+ CHECK_EQ("in compile", last_script_data_hit);
script3->Run();
f = v8::Local<v8::Function>::Cast(
env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
f->Call(env->Global(), 0, NULL);
CHECK_EQ(4, break_point_hit_count);
+ CHECK_EQ("in compile", last_script_data_hit);
}
ScriptResource* resource = new ScriptResource(source, source_length);
v8::Local<v8::String> script_source =
v8::String::NewExternal(isolate, resource);
- v8::Script::New(script_source, NULL, preparse);
+ v8::Script::New(script_source, NULL, preparse, v8::Local<v8::String>());
}
delete preparse;
i::FLAG_lazy = lazy_flag;