Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(476)

Side by Side Diff: src/liveedit.cc

Issue 652027: Basic implementation of liveedit feature (Closed)
Patch Set: add proper source headers Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/liveedit.h ('k') | src/liveedit-delay.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/liveedit.h ('k') | src/liveedit-delay.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698