Merge V8 5.2.361.47 DO NOT MERGE
https://chromium.googlesource.com/v8/v8/+/5.2.361.47
FPIIM-449
Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/debug/liveedit.cc b/src/debug/liveedit.cc
index 78ed6f1..50d60a1 100644
--- a/src/debug/liveedit.cc
+++ b/src/debug/liveedit.cc
@@ -13,6 +13,7 @@
#include "src/deoptimizer.h"
#include "src/frames-inl.h"
#include "src/global-handles.h"
+#include "src/interpreter/source-position-table.h"
#include "src/isolate-inl.h"
#include "src/messages.h"
#include "src/parsing/parser.h"
@@ -623,6 +624,8 @@
void FunctionInfoWrapper::SetFunctionCode(Handle<Code> function_code,
Handle<HeapObject> code_scope_info) {
+ // CompileForLiveEdit must deliver full-codegen code.
+ DCHECK(function_code->kind() == Code::FUNCTION);
Handle<JSValue> code_wrapper = WrapInJSValue(function_code);
this->SetField(kCodeOffset_, code_wrapper);
@@ -688,115 +691,6 @@
}
-class FunctionInfoListener {
- public:
- explicit FunctionInfoListener(Isolate* isolate) {
- current_parent_index_ = -1;
- len_ = 0;
- result_ = isolate->factory()->NewJSArray(10);
- }
-
- void FunctionStarted(FunctionLiteral* fun) {
- HandleScope scope(isolate());
- FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate());
- info.SetInitialProperties(fun->name(), fun->start_position(),
- fun->end_position(), fun->parameter_count(),
- fun->materialized_literal_count(),
- current_parent_index_);
- current_parent_index_ = len_;
- SetElementSloppy(result_, len_, info.GetJSArray());
- len_++;
- }
-
- void FunctionDone() {
- HandleScope scope(isolate());
- FunctionInfoWrapper info = FunctionInfoWrapper::cast(
- *JSReceiver::GetElement(isolate(), result_, current_parent_index_)
- .ToHandleChecked());
- current_parent_index_ = info.GetParentIndex();
- }
-
- // 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(
- *JSReceiver::GetElement(isolate(), result_, current_parent_index_)
- .ToHandleChecked());
- info.SetFunctionCode(function_code,
- Handle<HeapObject>(isolate()->heap()->null_value()));
- }
-
- // Saves full information about a function: its code, its scope info
- // and a SharedFunctionInfo object.
- void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope,
- Zone* zone) {
- if (!shared->IsSharedFunctionInfo()) {
- return;
- }
- FunctionInfoWrapper info = FunctionInfoWrapper::cast(
- *JSReceiver::GetElement(isolate(), result_, current_parent_index_)
- .ToHandleChecked());
- info.SetFunctionCode(Handle<Code>(shared->code()),
- Handle<HeapObject>(shared->scope_info()));
- info.SetSharedFunctionInfo(shared);
-
- Handle<Object> scope_info_list = SerializeFunctionScope(scope, zone);
- info.SetFunctionScopeInfo(scope_info_list);
- }
-
- Handle<JSArray> GetResult() { return result_; }
-
- private:
- Isolate* isolate() const { return result_->GetIsolate(); }
-
- Handle<Object> SerializeFunctionScope(Scope* scope, Zone* zone) {
- Handle<JSArray> scope_info_list = isolate()->factory()->NewJSArray(10);
- int scope_info_length = 0;
-
- // Saves some description of scope. It stores name and indexes of
- // variables in the whole scope chain. Null-named slots delimit
- // scopes of this chain.
- Scope* current_scope = scope;
- while (current_scope != NULL) {
- HandleScope handle_scope(isolate());
- ZoneList<Variable*> stack_list(current_scope->StackLocalCount(), zone);
- ZoneList<Variable*> context_list(
- current_scope->ContextLocalCount(), zone);
- ZoneList<Variable*> globals_list(current_scope->ContextGlobalCount(),
- zone);
- current_scope->CollectStackAndContextLocals(&stack_list, &context_list,
- &globals_list);
- context_list.Sort(&Variable::CompareIndex);
-
- for (int i = 0; i < context_list.length(); i++) {
- SetElementSloppy(scope_info_list,
- scope_info_length,
- context_list[i]->name());
- scope_info_length++;
- SetElementSloppy(
- scope_info_list,
- scope_info_length,
- Handle<Smi>(Smi::FromInt(context_list[i]->index()), isolate()));
- scope_info_length++;
- }
- SetElementSloppy(scope_info_list,
- scope_info_length,
- Handle<Object>(isolate()->heap()->null_value(),
- isolate()));
- scope_info_length++;
-
- current_scope = current_scope->outer_scope();
- }
-
- return scope_info_list;
- }
-
- Handle<JSArray> result_;
- int len_;
- int current_parent_index_;
-};
-
-
void LiveEdit::InitializeThreadLocal(Debug* debug) {
debug->thread_local_.frame_drop_mode_ = LiveEdit::FRAMES_UNTOUCHED;
}
@@ -832,11 +726,10 @@
Handle<String> source) {
Isolate* isolate = script->GetIsolate();
- FunctionInfoListener listener(isolate);
+ MaybeHandle<JSArray> infos;
Handle<Object> original_source =
Handle<Object>(script->source(), isolate);
script->set_source(*source);
- isolate->set_active_function_info_listener(&listener);
{
// Creating verbose TryCatch from public API is currently the only way to
@@ -845,7 +738,7 @@
try_catch.SetVerbose(true);
// A logical 'try' section.
- Compiler::CompileForLiveEdit(script);
+ infos = Compiler::CompileForLiveEdit(script);
}
// A logical 'catch' section.
@@ -883,11 +776,10 @@
}
// A logical 'finally' section.
- isolate->set_active_function_info_listener(NULL);
script->set_source(*original_source);
if (rethrow_exception.is_null()) {
- return listener.GetResult();
+ return infos.ToHandleChecked();
} else {
return isolate->Throw<JSArray>(rethrow_exception);
}
@@ -1116,9 +1008,23 @@
Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
- if (shared_info->code()->kind() == Code::FUNCTION) {
- Handle<Code> code = compile_info_wrapper.GetFunctionCode();
- ReplaceCodeObject(Handle<Code>(shared_info->code()), code);
+ if (shared_info->is_compiled()) {
+ Handle<Code> new_code = compile_info_wrapper.GetFunctionCode();
+ Handle<Code> old_code(shared_info->code());
+ if (shared_info->HasBytecodeArray()) {
+ // The old code is interpreted. If we clear the bytecode array, the
+ // interpreter entry trampoline will self-heal and go to compiled code.
+ shared_info->ClearBytecodeArray();
+ shared_info->ReplaceCode(*new_code);
+ } else {
+ DCHECK(old_code->kind() == Code::FUNCTION);
+ ReplaceCodeObject(old_code, new_code);
+ }
+ if (shared_info->HasDebugInfo()) {
+ // Existing break points will be re-applied. Reset the debug info here.
+ isolate->debug()->RemoveDebugInfoAndClearFromShared(
+ handle(shared_info->GetDebugInfo()));
+ }
Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
if (code_scope_info->IsFixedArray()) {
shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
@@ -1282,12 +1188,11 @@
static const int kMaximalBufferSize = 512*MB;
};
-
+namespace {
// Patch positions in code (changes relocation info section) and possibly
// returns new instance of code.
-static Handle<Code> PatchPositionsInCode(
- Handle<Code> code,
- Handle<JSArray> position_change_array) {
+Handle<Code> PatchPositionsInCode(Handle<Code> code,
+ Handle<JSArray> position_change_array) {
Isolate* isolate = code->GetIsolate();
RelocInfoBuffer buffer_writer(code->relocation_size(),
@@ -1328,6 +1233,24 @@
}
}
+void PatchPositionsInBytecodeArray(Handle<BytecodeArray> bytecode,
+ Handle<JSArray> position_change_array) {
+ Isolate* isolate = bytecode->GetIsolate();
+ Zone zone(isolate->allocator());
+ interpreter::SourcePositionTableBuilder builder(isolate, &zone);
+
+ for (interpreter::SourcePositionTableIterator iterator(
+ bytecode->source_position_table());
+ !iterator.done(); iterator.Advance()) {
+ int position = iterator.source_position();
+ int new_position = TranslatePosition(position, position_change_array);
+ builder.AddPosition(iterator.bytecode_offset(), new_position,
+ iterator.is_statement());
+ }
+
+ bytecode->set_source_position_table(*builder.ToSourcePositionTable());
+}
+} // namespace
void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array,
Handle<JSArray> position_change_array) {
@@ -1358,6 +1281,9 @@
// untouched).
ReplaceCodeObject(Handle<Code>(info->code()), patched_code);
}
+ } else if (info->HasBytecodeArray()) {
+ PatchPositionsInBytecodeArray(Handle<BytecodeArray>(info->bytecode_array()),
+ position_change_array);
}
}
@@ -1374,8 +1300,7 @@
copy->set_type(original->type());
copy->set_context_data(original->context_data());
copy->set_eval_from_shared(original->eval_from_shared());
- copy->set_eval_from_instructions_offset(
- original->eval_from_instructions_offset());
+ copy->set_eval_from_position(original->eval_from_position());
// Copy all the flags, but clear compilation state.
copy->set_flags(original->flags());
@@ -1555,6 +1480,13 @@
top_frame = frames[top_frame_index - 2];
*mode = LiveEdit::CURRENTLY_SET_MODE;
frame_has_padding = false;
+ } else if (pre_top_frame_code->kind() == Code::BYTECODE_HANDLER) {
+ // Interpreted bytecode takes up two stack frames, one for the bytecode
+ // handler and one for the interpreter entry trampoline. Therefore we shift
+ // up by one frame.
+ *mode = LiveEdit::FRAME_DROPPED_IN_DIRECT_CALL;
+ pre_top_frame = frames[top_frame_index - 2];
+ top_frame = frames[top_frame_index - 1];
} else {
return "Unknown structure of stack above changing function";
}
@@ -1792,7 +1724,8 @@
// Adjust break_frame after some frames has been dropped.
StackFrame::Id new_id = StackFrame::NO_ID;
for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) {
- if (frames[i]->type() == StackFrame::JAVA_SCRIPT) {
+ if (frames[i]->type() == StackFrame::JAVA_SCRIPT ||
+ frames[i]->type() == StackFrame::INTERPRETED) {
new_id = frames[i]->id();
break;
}
@@ -2004,40 +1937,107 @@
return NULL;
}
+Handle<JSArray> LiveEditFunctionTracker::Collect(FunctionLiteral* node,
+ Handle<Script> script,
+ Zone* zone, Isolate* isolate) {
+ LiveEditFunctionTracker visitor(script, zone, isolate);
+ visitor.VisitFunctionLiteral(node);
+ return visitor.result_;
+}
-LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
- FunctionLiteral* fun)
- : isolate_(isolate) {
- if (isolate_->active_function_info_listener() != NULL) {
- isolate_->active_function_info_listener()->FunctionStarted(fun);
+LiveEditFunctionTracker::LiveEditFunctionTracker(Handle<Script> script,
+ Zone* zone, Isolate* isolate)
+ : AstTraversalVisitor(isolate) {
+ current_parent_index_ = -1;
+ isolate_ = isolate;
+ len_ = 0;
+ result_ = isolate->factory()->NewJSArray(10);
+ script_ = script;
+ zone_ = zone;
+}
+
+void LiveEditFunctionTracker::VisitFunctionLiteral(FunctionLiteral* node) {
+ Scope* scope = node->scope();
+
+ // FunctionStarted is called in pre-order.
+ FunctionStarted(node);
+
+ VisitDeclarations(scope->declarations());
+ VisitStatements(node->body());
+
+ // FunctionDone are called in post-order.
+ // TODO(jgruber): If required, replace the (linear cost)
+ // FindSharedFunctionInfo call with a more efficient implementation.
+ Handle<SharedFunctionInfo> info =
+ script_->FindSharedFunctionInfo(node).ToHandleChecked();
+ FunctionDone(info, scope);
+}
+
+void LiveEditFunctionTracker::FunctionStarted(FunctionLiteral* fun) {
+ HandleScope handle_scope(isolate_);
+ FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate_);
+ info.SetInitialProperties(fun->name(), fun->start_position(),
+ fun->end_position(), fun->parameter_count(),
+ fun->materialized_literal_count(),
+ current_parent_index_);
+ current_parent_index_ = len_;
+ SetElementSloppy(result_, len_, info.GetJSArray());
+ len_++;
+}
+
+// Saves full information about a function: its code, its scope info
+// and a SharedFunctionInfo object.
+void LiveEditFunctionTracker::FunctionDone(Handle<SharedFunctionInfo> shared,
+ Scope* scope) {
+ HandleScope handle_scope(isolate_);
+ FunctionInfoWrapper info = FunctionInfoWrapper::cast(
+ *JSReceiver::GetElement(isolate_, result_, current_parent_index_)
+ .ToHandleChecked());
+ info.SetFunctionCode(Handle<Code>(shared->code()),
+ Handle<HeapObject>(shared->scope_info()));
+ info.SetSharedFunctionInfo(shared);
+
+ Handle<Object> scope_info_list = SerializeFunctionScope(scope);
+ info.SetFunctionScopeInfo(scope_info_list);
+
+ current_parent_index_ = info.GetParentIndex();
+}
+
+Handle<Object> LiveEditFunctionTracker::SerializeFunctionScope(Scope* scope) {
+ Handle<JSArray> scope_info_list = isolate_->factory()->NewJSArray(10);
+ int scope_info_length = 0;
+
+ // Saves some description of scope. It stores name and indexes of
+ // variables in the whole scope chain. Null-named slots delimit
+ // scopes of this chain.
+ Scope* current_scope = scope;
+ while (current_scope != NULL) {
+ HandleScope handle_scope(isolate_);
+ ZoneList<Variable*> stack_list(current_scope->StackLocalCount(), zone_);
+ ZoneList<Variable*> context_list(current_scope->ContextLocalCount(), zone_);
+ ZoneList<Variable*> globals_list(current_scope->ContextGlobalCount(),
+ zone_);
+ current_scope->CollectStackAndContextLocals(&stack_list, &context_list,
+ &globals_list);
+ context_list.Sort(&Variable::CompareIndex);
+
+ for (int i = 0; i < context_list.length(); i++) {
+ SetElementSloppy(scope_info_list, scope_info_length,
+ context_list[i]->name());
+ scope_info_length++;
+ SetElementSloppy(
+ scope_info_list, scope_info_length,
+ Handle<Smi>(Smi::FromInt(context_list[i]->index()), isolate_));
+ scope_info_length++;
+ }
+ SetElementSloppy(scope_info_list, scope_info_length,
+ Handle<Object>(isolate_->heap()->null_value(), isolate_));
+ scope_info_length++;
+
+ current_scope = current_scope->outer_scope();
}
-}
-
-LiveEditFunctionTracker::~LiveEditFunctionTracker() {
- if (isolate_->active_function_info_listener() != NULL) {
- isolate_->active_function_info_listener()->FunctionDone();
- }
-}
-
-
-void LiveEditFunctionTracker::RecordFunctionInfo(
- Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
- Zone* zone) {
- if (isolate_->active_function_info_listener() != NULL) {
- isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope(),
- zone);
- }
-}
-
-
-void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
- isolate_->active_function_info_listener()->FunctionCode(code);
-}
-
-
-bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
- return isolate->active_function_info_listener() != NULL;
+ return scope_info_list;
}
} // namespace internal