OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 21 matching lines...) Expand all Loading... |
32 #include "compiler.h" | 32 #include "compiler.h" |
33 #include "oprofile-agent.h" | 33 #include "oprofile-agent.h" |
34 #include "scopes.h" | 34 #include "scopes.h" |
35 #include "global-handles.h" | 35 #include "global-handles.h" |
36 #include "debug.h" | 36 #include "debug.h" |
37 | 37 |
38 namespace v8 { | 38 namespace v8 { |
39 namespace internal { | 39 namespace internal { |
40 | 40 |
41 | 41 |
42 class FunctionInfoListener { | 42 #ifdef ENABLE_DEBUGGER_SUPPORT |
43 public: | 43 |
44 void FunctionStarted(FunctionLiteral* fun) { | 44 static void CompileScriptForTracker(Handle<Script> script) { |
45 // Implementation follows. | 45 const bool is_eval = false; |
| 46 const bool is_global = true; |
| 47 // TODO: support extensions. |
| 48 Extension* extension = NULL; |
| 49 |
| 50 PostponeInterruptsScope postpone; |
| 51 |
| 52 // Only allow non-global compiles for eval. |
| 53 ASSERT(is_eval || is_global); |
| 54 |
| 55 // Build AST. |
| 56 ScriptDataImpl* pre_data = NULL; |
| 57 FunctionLiteral* lit = MakeAST(is_global, script, extension, pre_data); |
| 58 |
| 59 // Check for parse errors. |
| 60 if (lit == NULL) { |
| 61 ASSERT(Top::has_pending_exception()); |
| 62 return; |
46 } | 63 } |
47 | 64 |
48 void FunctionDone() { | 65 // Compile the code. |
49 // Implementation follows. | 66 CompilationInfo info(lit, script, is_eval); |
| 67 Handle<Code> code = MakeCodeForLiveEdit(&info); |
| 68 |
| 69 // Check for stack-overflow exceptions. |
| 70 if (code.is_null()) { |
| 71 Top::StackOverflow(); |
| 72 return; |
50 } | 73 } |
51 | |
52 void FunctionScope(Scope* scope) { | |
53 // Implementation follows. | |
54 } | |
55 | |
56 void FunctionCode(Handle<Code> function_code) { | |
57 // Implementation follows. | |
58 } | |
59 }; | |
60 | |
61 static FunctionInfoListener* active_function_info_listener = NULL; | |
62 | |
63 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) { | |
64 if (active_function_info_listener != NULL) { | |
65 active_function_info_listener->FunctionStarted(fun); | |
66 } | |
67 } | |
68 LiveEditFunctionTracker::~LiveEditFunctionTracker() { | |
69 if (active_function_info_listener != NULL) { | |
70 active_function_info_listener->FunctionDone(); | |
71 } | |
72 } | |
73 void LiveEditFunctionTracker::RecordFunctionCode(Handle<Code> code) { | |
74 if (active_function_info_listener != NULL) { | |
75 active_function_info_listener->FunctionCode(code); | |
76 } | |
77 } | |
78 void LiveEditFunctionTracker::RecordFunctionScope(Scope* scope) { | |
79 if (active_function_info_listener != NULL) { | |
80 active_function_info_listener->FunctionScope(scope); | |
81 } | |
82 } | |
83 bool LiveEditFunctionTracker::IsActive() { | |
84 return active_function_info_listener != NULL; | |
85 } | 74 } |
86 | 75 |
87 // Unwraps JSValue object, returning its field "value" | 76 // Unwraps JSValue object, returning its field "value" |
88 static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) { | 77 static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) { |
89 return Handle<Object>(jsValue->value()); | 78 return Handle<Object>(jsValue->value()); |
90 } | 79 } |
91 | 80 |
92 // Wraps any object into a OpaqueReference, that will hide the object | 81 // Wraps any object into a OpaqueReference, that will hide the object |
93 // from JavaScript. | 82 // from JavaScript. |
94 static Handle<JSValue> WrapInJSValue(Object* object) { | 83 static Handle<JSValue> WrapInJSValue(Object* object) { |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 | 168 |
180 private: | 169 private: |
181 static const int kFunctionNameOffset_ = 0; | 170 static const int kFunctionNameOffset_ = 0; |
182 static const int kStartPositionOffset_ = 1; | 171 static const int kStartPositionOffset_ = 1; |
183 static const int kEndPositionOffset_ = 2; | 172 static const int kEndPositionOffset_ = 2; |
184 static const int kParamNumOffset_ = 3; | 173 static const int kParamNumOffset_ = 3; |
185 static const int kCodeOffset_ = 4; | 174 static const int kCodeOffset_ = 4; |
186 static const int kScopeInfoOffset_ = 5; | 175 static const int kScopeInfoOffset_ = 5; |
187 static const int kParentIndexOffset_ = 6; | 176 static const int kParentIndexOffset_ = 6; |
188 static const int kSize_ = 7; | 177 static const int kSize_ = 7; |
| 178 |
| 179 friend class JSArrayBasedStruct<FunctionInfoWrapper>; |
189 }; | 180 }; |
190 | 181 |
191 // Wraps SharedFunctionInfo along with some of its fields for passing it | 182 // Wraps SharedFunctionInfo along with some of its fields for passing it |
192 // back to JavaScript. SharedFunctionInfo object itself is additionally | 183 // back to JavaScript. SharedFunctionInfo object itself is additionally |
193 // wrapped into BlindReference for sanitizing reasons. | 184 // wrapped into BlindReference for sanitizing reasons. |
194 class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> { | 185 class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> { |
195 public: | 186 public: |
196 explicit SharedInfoWrapper(Handle<JSArray> array) | 187 explicit SharedInfoWrapper(Handle<JSArray> array) |
197 : JSArrayBasedStruct<SharedInfoWrapper>(array) { | 188 : JSArrayBasedStruct<SharedInfoWrapper>(array) { |
198 } | 189 } |
(...skipping 13 matching lines...) Expand all Loading... |
212 Handle<Object> raw_result = UnwrapJSValue(value_wrapper); | 203 Handle<Object> raw_result = UnwrapJSValue(value_wrapper); |
213 return Handle<SharedFunctionInfo>::cast(raw_result); | 204 return Handle<SharedFunctionInfo>::cast(raw_result); |
214 } | 205 } |
215 | 206 |
216 private: | 207 private: |
217 static const int kFunctionNameOffset_ = 0; | 208 static const int kFunctionNameOffset_ = 0; |
218 static const int kStartPositionOffset_ = 1; | 209 static const int kStartPositionOffset_ = 1; |
219 static const int kEndPositionOffset_ = 2; | 210 static const int kEndPositionOffset_ = 2; |
220 static const int kSharedInfoOffset_ = 3; | 211 static const int kSharedInfoOffset_ = 3; |
221 static const int kSize_ = 4; | 212 static const int kSize_ = 4; |
| 213 |
| 214 friend class JSArrayBasedStruct<SharedInfoWrapper>; |
222 }; | 215 }; |
223 | 216 |
| 217 class FunctionInfoListener { |
| 218 public: |
| 219 FunctionInfoListener() { |
| 220 current_parent_index_ = -1; |
| 221 len_ = 0; |
| 222 result_ = Factory::NewJSArray(10); |
| 223 } |
| 224 |
| 225 void FunctionStarted(FunctionLiteral* fun) { |
| 226 HandleScope scope; |
| 227 FunctionInfoWrapper info = FunctionInfoWrapper::Create(); |
| 228 info.SetInitialProperties(fun->name(), fun->start_position(), |
| 229 fun->end_position(), fun->num_parameters(), |
| 230 current_parent_index_); |
| 231 current_parent_index_ = len_; |
| 232 SetElement(result_, len_, info.GetJSArray()); |
| 233 len_++; |
| 234 } |
| 235 |
| 236 void FunctionDone() { |
| 237 HandleScope scope; |
| 238 FunctionInfoWrapper info = |
| 239 FunctionInfoWrapper::cast(result_->GetElement(current_parent_index_)); |
| 240 current_parent_index_ = info.GetParentIndex(); |
| 241 } |
| 242 |
| 243 void FunctionScope(Scope* scope) { |
| 244 HandleScope handle_scope; |
| 245 |
| 246 Handle<JSArray> scope_info_list = Factory::NewJSArray(10); |
| 247 int scope_info_length = 0; |
| 248 |
| 249 // Saves some description of scope. It stores name and indexes of |
| 250 // variables in the whole scope chain. Null-named slots delimit |
| 251 // scopes of this chain. |
| 252 Scope* outer_scope = scope->outer_scope(); |
| 253 if (outer_scope == NULL) { |
| 254 return; |
| 255 } |
| 256 do { |
| 257 ZoneList<Variable*> list(10); |
| 258 outer_scope->CollectUsedVariables(&list); |
| 259 int j = 0; |
| 260 for (int i = 0; i < list.length(); i++) { |
| 261 Variable* var1 = list[i]; |
| 262 Slot* slot = var1->slot(); |
| 263 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 264 if (j != i) { |
| 265 list[j] = var1; |
| 266 } |
| 267 j++; |
| 268 } |
| 269 } |
| 270 |
| 271 // Sort it. |
| 272 for (int k = 1; k < j; k++) { |
| 273 int l = k; |
| 274 for (int m = k + 1; m < j; m++) { |
| 275 if (list[l]->slot()->index() > list[m]->slot()->index()) { |
| 276 l = m; |
| 277 } |
| 278 } |
| 279 list[k] = list[l]; |
| 280 } |
| 281 for (int i = 0; i < j; i++) { |
| 282 SetElement(scope_info_list, scope_info_length, list[i]->name()); |
| 283 scope_info_length++; |
| 284 SetElement(scope_info_list, scope_info_length, |
| 285 Handle<Smi>(Smi::FromInt(list[i]->slot()->index()))); |
| 286 scope_info_length++; |
| 287 } |
| 288 SetElement(scope_info_list, scope_info_length, |
| 289 Handle<Object>(Heap::null_value())); |
| 290 scope_info_length++; |
| 291 |
| 292 outer_scope = outer_scope->outer_scope(); |
| 293 } while (outer_scope != NULL); |
| 294 |
| 295 FunctionInfoWrapper info = |
| 296 FunctionInfoWrapper::cast(result_->GetElement(current_parent_index_)); |
| 297 info.SetScopeInfo(scope_info_list); |
| 298 } |
| 299 |
| 300 void FunctionCode(Handle<Code> function_code) { |
| 301 FunctionInfoWrapper info = |
| 302 FunctionInfoWrapper::cast(result_->GetElement(current_parent_index_)); |
| 303 info.SetFunctionCode(function_code); |
| 304 } |
| 305 |
| 306 Handle<JSArray> GetResult() { |
| 307 return result_; |
| 308 } |
| 309 |
| 310 private: |
| 311 Handle<JSArray> result_; |
| 312 int len_; |
| 313 int current_parent_index_; |
| 314 }; |
| 315 |
| 316 static FunctionInfoListener* active_function_info_listener = NULL; |
| 317 |
| 318 JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script, |
| 319 Handle<String> source) { |
| 320 CompilationZoneScope zone_scope(DELETE_ON_EXIT); |
| 321 |
| 322 FunctionInfoListener listener; |
| 323 script->set_source(*source); |
| 324 active_function_info_listener = &listener; |
| 325 Handle<Object> original_source = Handle<Object>(script->source()); |
| 326 CompileScriptForTracker(script); |
| 327 active_function_info_listener = NULL; |
| 328 script->set_source(*original_source); |
| 329 |
| 330 return *(listener.GetResult()); |
| 331 } |
| 332 |
| 333 |
| 334 void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) { |
| 335 HandleScope scope; |
| 336 int len = Smi::cast(array->length())->value(); |
| 337 for (int i = 0; i < len; i++) { |
| 338 Handle<SharedFunctionInfo> info( |
| 339 SharedFunctionInfo::cast(array->GetElement(i))); |
| 340 SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create(); |
| 341 Handle<String> name_handle(String::cast(info->name())); |
| 342 info_wrapper.SetProperties(name_handle, info->start_position(), |
| 343 info->end_position(), info); |
| 344 array->SetElement(i, *(info_wrapper.GetJSArray())); |
| 345 } |
| 346 } |
| 347 |
| 348 |
| 349 void LiveEdit::ReplaceFunctionCode(Handle<JSArray> new_compile_info_array, |
| 350 Handle<JSArray> shared_info_array) { |
| 351 HandleScope scope; |
| 352 |
| 353 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array); |
| 354 SharedInfoWrapper shared_info_wrapper(shared_info_array); |
| 355 |
| 356 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo(); |
| 357 |
| 358 shared_info->set_code(*(compile_info_wrapper.GetFunctionCode()), |
| 359 UPDATE_WRITE_BARRIER); |
| 360 shared_info->set_start_position(compile_info_wrapper.GetStartPosition()); |
| 361 shared_info->set_end_position(compile_info_wrapper.GetEndPosition()); |
| 362 // update breakpoints, original code, constructor stub |
| 363 } |
| 364 |
| 365 |
| 366 void LiveEdit::RelinkFunctionToScript(Handle<JSArray> shared_info_array, |
| 367 Handle<Script> script_handle) { |
| 368 SharedInfoWrapper shared_info_wrapper(shared_info_array); |
| 369 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo(); |
| 370 |
| 371 shared_info->set_script(*script_handle); |
| 372 } |
| 373 |
| 374 |
| 375 // For a script text change (defined as position_change_array), translates |
| 376 // position in unchanged text to position in changed text. |
| 377 // Text change is a set of non-overlapping regions in text, that have changed |
| 378 // their contents and length. It is specified as array of groups of 3 numbers: |
| 379 // (change_begin, change_end, change_end_new_position). |
| 380 // Each group describes a change in text; groups are sorted by change_begin. |
| 381 // Only position in text beyond any changes may be successfully translated. |
| 382 // If a positions is inside some region that changed, result is currently |
| 383 // undefined. |
| 384 static int TranslatePosition(int original_position, |
| 385 Handle<JSArray> position_change_array) { |
| 386 int position_diff = 0; |
| 387 int array_len = Smi::cast(position_change_array->length())->value(); |
| 388 // TODO: binary search may be used here |
| 389 for (int i = 0; i < array_len; i += 3) { |
| 390 int chunk_start = |
| 391 Smi::cast(position_change_array->GetElement(i))->value(); |
| 392 int chunk_end = |
| 393 Smi::cast(position_change_array->GetElement(i + 1))->value(); |
| 394 int chunk_changed_end = |
| 395 Smi::cast(position_change_array->GetElement(i + 2))->value(); |
| 396 position_diff = chunk_changed_end - chunk_end; |
| 397 if (original_position < chunk_start) { |
| 398 break; |
| 399 } |
| 400 // Position mustn't be inside a chunk. |
| 401 ASSERT(original_position >= chunk_end); |
| 402 } |
| 403 |
| 404 return original_position + position_diff; |
| 405 } |
| 406 |
| 407 |
| 408 void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array, |
| 409 Handle<JSArray> position_change_array) { |
| 410 SharedInfoWrapper shared_info_wrapper(shared_info_array); |
| 411 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo(); |
| 412 |
| 413 info->set_start_position(TranslatePosition(info->start_position(), |
| 414 position_change_array)); |
| 415 info->set_end_position(TranslatePosition(info->end_position(), |
| 416 position_change_array)); |
| 417 |
| 418 // Also patch rinfos (both in working code and original code), breakpoints. |
| 419 } |
| 420 |
| 421 |
| 422 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) { |
| 423 if (active_function_info_listener != NULL) { |
| 424 active_function_info_listener->FunctionStarted(fun); |
| 425 } |
| 426 } |
| 427 |
| 428 |
| 429 LiveEditFunctionTracker::~LiveEditFunctionTracker() { |
| 430 if (active_function_info_listener != NULL) { |
| 431 active_function_info_listener->FunctionDone(); |
| 432 } |
| 433 } |
| 434 |
| 435 |
| 436 void LiveEditFunctionTracker::RecordFunctionCode(Handle<Code> code) { |
| 437 if (active_function_info_listener != NULL) { |
| 438 active_function_info_listener->FunctionCode(code); |
| 439 } |
| 440 } |
| 441 |
| 442 |
| 443 void LiveEditFunctionTracker::RecordFunctionScope(Scope* scope) { |
| 444 if (active_function_info_listener != NULL) { |
| 445 active_function_info_listener->FunctionScope(scope); |
| 446 } |
| 447 } |
| 448 |
| 449 |
| 450 bool LiveEditFunctionTracker::IsActive() { |
| 451 return active_function_info_listener != NULL; |
| 452 } |
| 453 |
| 454 |
| 455 #else // ENABLE_DEBUGGER_SUPPORT |
| 456 |
| 457 // This ifdef-else-endif section provides working or stub implementation of |
| 458 // LiveEditFunctionTracker. |
| 459 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) { |
| 460 } |
| 461 |
| 462 |
| 463 LiveEditFunctionTracker::~LiveEditFunctionTracker() { |
| 464 } |
| 465 |
| 466 |
| 467 void LiveEditFunctionTracker::RecordFunctionCode(Handle<Code> code) { |
| 468 } |
| 469 |
| 470 |
| 471 void LiveEditFunctionTracker::RecordFunctionScope(Scope* scope) { |
| 472 } |
| 473 |
| 474 |
| 475 bool LiveEditFunctionTracker::IsActive() { |
| 476 return false; |
| 477 } |
| 478 |
| 479 #endif // ENABLE_DEBUGGER_SUPPORT |
| 480 |
224 | 481 |
225 | 482 |
226 } } // namespace v8::internal | 483 } } // namespace v8::internal |
OLD | NEW |