| Index: src/liveedit.cc
|
| diff --git a/src/liveedit.cc b/src/liveedit.cc
|
| index ba417e53c7274f67d277f13705a83456712682bb..cf49bf7697049ac3a09b9cf447f76a50a3ed3fce 100644
|
| --- a/src/liveedit.cc
|
| +++ b/src/liveedit.cc
|
| @@ -417,6 +417,8 @@ static void CompileScriptForTracker(Handle<Script> script) {
|
|
|
| // Compile the code.
|
| CompilationInfo info(lit, script, is_eval);
|
| +
|
| + LiveEditFunctionTracker tracker(lit);
|
| Handle<Code> code = MakeCodeForLiveEdit(&info);
|
|
|
| // Check for stack-overflow exceptions.
|
| @@ -424,6 +426,7 @@ static void CompileScriptForTracker(Handle<Script> script) {
|
| Top::StackOverflow();
|
| return;
|
| }
|
| + tracker.RecordRootFunctionInfo(code);
|
| }
|
|
|
| // Unwraps JSValue object, returning its field "value"
|
| @@ -501,9 +504,13 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
|
| Handle<JSValue> wrapper = WrapInJSValue(*function_code);
|
| this->SetField(kCodeOffset_, wrapper);
|
| }
|
| - void SetScopeInfo(Handle<JSArray> scope_info_array) {
|
| + void SetScopeInfo(Handle<Object> scope_info_array) {
|
| this->SetField(kScopeInfoOffset_, scope_info_array);
|
| }
|
| + void SetSharedFunctionInfo(Handle<SharedFunctionInfo> info) {
|
| + Handle<JSValue> info_holder = WrapInJSValue(*info);
|
| + this->SetField(kSharedFunctionInfoOffset_, info_holder);
|
| + }
|
| int GetParentIndex() {
|
| return this->GetSmiValueField(kParentIndexOffset_);
|
| }
|
| @@ -527,7 +534,8 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
|
| static const int kCodeOffset_ = 4;
|
| static const int kScopeInfoOffset_ = 5;
|
| static const int kParentIndexOffset_ = 6;
|
| - static const int kSize_ = 7;
|
| + static const int kSharedFunctionInfoOffset_ = 7;
|
| + static const int kSize_ = 8;
|
|
|
| friend class JSArrayBasedStruct<FunctionInfoWrapper>;
|
| };
|
| @@ -593,7 +601,11 @@ class FunctionInfoListener {
|
| current_parent_index_ = info.GetParentIndex();
|
| }
|
|
|
| - void FunctionScope(Scope* scope) {
|
| +// TODO(LiveEdit): Move private method below.
|
| +// This private section was created here to avoid moving the function
|
| +// to keep already complex diff simpler.
|
| + private:
|
| + Object* SerializeFunctionScope(Scope* scope) {
|
| HandleScope handle_scope;
|
|
|
| Handle<JSArray> scope_info_list = Factory::NewJSArray(10);
|
| @@ -604,7 +616,7 @@ class FunctionInfoListener {
|
| // scopes of this chain.
|
| Scope* outer_scope = scope->outer_scope();
|
| if (outer_scope == NULL) {
|
| - return;
|
| + return Heap::undefined_value();
|
| }
|
| do {
|
| ZoneList<Variable*> list(10);
|
| @@ -645,17 +657,33 @@ class FunctionInfoListener {
|
| outer_scope = outer_scope->outer_scope();
|
| } while (outer_scope != NULL);
|
|
|
| - FunctionInfoWrapper info =
|
| - FunctionInfoWrapper::cast(result_->GetElement(current_parent_index_));
|
| - info.SetScopeInfo(scope_info_list);
|
| + return *scope_info_list;
|
| }
|
|
|
| + public:
|
| + // Saves only function code, because for a script function we
|
| + // may never create a SharedFunctionInfo object.
|
| void FunctionCode(Handle<Code> function_code) {
|
| FunctionInfoWrapper info =
|
| FunctionInfoWrapper::cast(result_->GetElement(current_parent_index_));
|
| info.SetFunctionCode(function_code);
|
| }
|
|
|
| + // Saves full information about a function: its code, its scope info
|
| + // and a SharedFunctionInfo object.
|
| + void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope) {
|
| + if (!shared->IsSharedFunctionInfo()) {
|
| + return;
|
| + }
|
| + FunctionInfoWrapper info =
|
| + FunctionInfoWrapper::cast(result_->GetElement(current_parent_index_));
|
| + info.SetFunctionCode(Handle<Code>(shared->code()));
|
| + info.SetSharedFunctionInfo(shared);
|
| +
|
| + Handle<Object> scope_info_list(SerializeFunctionScope(scope));
|
| + info.SetScopeInfo(scope_info_list);
|
| + }
|
| +
|
| Handle<JSArray> GetResult() {
|
| return result_;
|
| }
|
| @@ -815,7 +843,6 @@ void LiveEdit::ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,
|
|
|
| Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
|
|
|
| -
|
| if (IsJSFunctionCode(shared_info->code())) {
|
| ReplaceCodeObject(shared_info->code(),
|
| *(compile_info_wrapper.GetFunctionCode()));
|
| @@ -839,11 +866,10 @@ void LiveEdit::ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,
|
|
|
| // TODO(635): Eval caches its scripts (same text -- same compiled info).
|
| // Make sure we clear such caches.
|
| -void LiveEdit::RelinkFunctionToScript(Handle<JSArray> shared_info_array,
|
| - Handle<Script> script_handle) {
|
| - SharedInfoWrapper shared_info_wrapper(shared_info_array);
|
| - Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
|
| -
|
| +void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
|
| + Handle<Object> script_handle) {
|
| + Handle<SharedFunctionInfo> shared_info =
|
| + Handle<SharedFunctionInfo>::cast(UnwrapJSValue(function_wrapper));
|
| shared_info->set_script(*script_handle);
|
| }
|
|
|
| @@ -998,20 +1024,7 @@ static Handle<Code> PatchPositionsInCode(Handle<Code> code,
|
| }
|
|
|
|
|
| -static Handle<Object> GetBreakPointObjectsForJS(
|
| - Handle<BreakPointInfo> break_point_info) {
|
| - if (break_point_info->break_point_objects()->IsFixedArray()) {
|
| - Handle<FixedArray> fixed_array(
|
| - FixedArray::cast(break_point_info->break_point_objects()));
|
| - Handle<Object> array = Factory::NewJSArrayWithElements(fixed_array);
|
| - return array;
|
| - } else {
|
| - return Handle<Object>(break_point_info->break_point_objects());
|
| - }
|
| -}
|
| -
|
| -
|
| -Handle<JSArray> LiveEdit::PatchFunctionPositions(
|
| +void LiveEdit::PatchFunctionPositions(
|
| Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
|
| SharedInfoWrapper shared_info_wrapper(shared_info_array);
|
| Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
|
| @@ -1040,45 +1053,71 @@ Handle<JSArray> LiveEdit::PatchFunctionPositions(
|
| ReplaceCodeObject(info->code(), *patched_code);
|
| }
|
| }
|
| +}
|
|
|
|
|
| - Handle<JSArray> result = Factory::NewJSArray(0);
|
| - int result_len = 0;
|
| +static Handle<Script> CreateScriptCopy(Handle<Script> original) {
|
| + Handle<String> original_source(String::cast(original->source()));
|
|
|
| - if (info->debug_info()->IsDebugInfo()) {
|
| - Handle<DebugInfo> debug_info(DebugInfo::cast(info->debug_info()));
|
| - Handle<Code> patched_orig_code =
|
| - PatchPositionsInCode(Handle<Code>(debug_info->original_code()),
|
| - position_change_array);
|
| - if (*patched_orig_code != debug_info->original_code()) {
|
| - // Do not use expensive ReplaceCodeObject for original_code, because we
|
| - // do not expect any other references except this one.
|
| - debug_info->set_original_code(*patched_orig_code);
|
| - }
|
| + Handle<Script> copy = Factory::NewScript(original_source);
|
|
|
| - Handle<FixedArray> break_point_infos(debug_info->break_points());
|
| - for (int i = 0; i < break_point_infos->length(); i++) {
|
| - if (!break_point_infos->get(i)->IsBreakPointInfo()) {
|
| - continue;
|
| - }
|
| - Handle<BreakPointInfo> info(
|
| - BreakPointInfo::cast(break_point_infos->get(i)));
|
| - int old_in_script_position = info->source_position()->value() +
|
| - old_function_start;
|
| - int new_in_script_position = TranslatePosition(old_in_script_position,
|
| - position_change_array);
|
| - info->set_source_position(
|
| - Smi::FromInt(new_in_script_position - new_function_start));
|
| - if (old_in_script_position != new_in_script_position) {
|
| - SetElement(result, result_len,
|
| - Handle<Smi>(Smi::FromInt(new_in_script_position)));
|
| - SetElement(result, result_len + 1,
|
| - GetBreakPointObjectsForJS(info));
|
| - result_len += 2;
|
| + 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_compilation_type(original->compilation_type());
|
| + copy->set_eval_from_shared(original->eval_from_shared());
|
| + copy->set_eval_from_instructions_offset(
|
| + original->eval_from_instructions_offset());
|
| +
|
| + return copy;
|
| +}
|
| +
|
| +
|
| +Object* LiveEdit::ChangeScriptSource(Handle<Script> original_script,
|
| + Handle<String> new_source,
|
| + Handle<Object> old_script_name) {
|
| + Handle<Object> old_script_object;
|
| + if (old_script_name->IsString()) {
|
| + Handle<Script> old_script = CreateScriptCopy(original_script);
|
| + old_script->set_name(String::cast(*old_script_name));
|
| + old_script_object = old_script;
|
| + Debugger::OnAfterCompile(old_script, Debugger::SEND_WHEN_DEBUGGING);
|
| + } else {
|
| + old_script_object = Handle<Object>(Heap::null_value());
|
| + }
|
| +
|
| + original_script->set_source(*new_source);
|
| +
|
| + // Drop line ends so that they will be recalculated.
|
| + original_script->set_line_ends(Heap::undefined_value());
|
| +
|
| + return *old_script_object;
|
| +}
|
| +
|
| +
|
| +
|
| +void LiveEdit::ReplaceRefToNestedFunction(
|
| + Handle<JSValue> parent_function_wrapper,
|
| + Handle<JSValue> orig_function_wrapper,
|
| + Handle<JSValue> subst_function_wrapper) {
|
| +
|
| + Handle<SharedFunctionInfo> parent_shared =
|
| + Handle<SharedFunctionInfo>::cast(UnwrapJSValue(parent_function_wrapper));
|
| + Handle<SharedFunctionInfo> orig_shared =
|
| + Handle<SharedFunctionInfo>::cast(UnwrapJSValue(orig_function_wrapper));
|
| + Handle<SharedFunctionInfo> subst_shared =
|
| + Handle<SharedFunctionInfo>::cast(UnwrapJSValue(subst_function_wrapper));
|
| +
|
| + for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
|
| + if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
|
| + if (it.rinfo()->target_object() == *orig_shared) {
|
| + it.rinfo()->set_target_object(*subst_shared);
|
| }
|
| }
|
| }
|
| - return result;
|
| }
|
|
|
|
|
| @@ -1362,17 +1401,16 @@ LiveEditFunctionTracker::~LiveEditFunctionTracker() {
|
| }
|
|
|
|
|
| -void LiveEditFunctionTracker::RecordFunctionCode(Handle<Code> code) {
|
| +void LiveEditFunctionTracker::RecordFunctionInfo(
|
| + Handle<SharedFunctionInfo> info, FunctionLiteral* lit) {
|
| if (active_function_info_listener != NULL) {
|
| - active_function_info_listener->FunctionCode(code);
|
| + active_function_info_listener->FunctionInfo(info, lit->scope());
|
| }
|
| }
|
|
|
|
|
| -void LiveEditFunctionTracker::RecordFunctionScope(Scope* scope) {
|
| - if (active_function_info_listener != NULL) {
|
| - active_function_info_listener->FunctionScope(scope);
|
| - }
|
| +void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
|
| + active_function_info_listener->FunctionCode(code);
|
| }
|
|
|
|
|
| @@ -1393,11 +1431,12 @@ LiveEditFunctionTracker::~LiveEditFunctionTracker() {
|
| }
|
|
|
|
|
| -void LiveEditFunctionTracker::RecordFunctionCode(Handle<Code> code) {
|
| +void LiveEditFunctionTracker::RecordFunctionInfo(
|
| + Handle<SharedFunctionInfo> info, FunctionLiteral* lit) {
|
| }
|
|
|
|
|
| -void LiveEditFunctionTracker::RecordFunctionScope(Scope* scope) {
|
| +void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
|
| }
|
|
|
|
|
|
|