Commit 22594d10 authored by Yang Guo's avatar Yang Guo Committed by Commit Bot

Revert "[debug] liveedit in native"

This reverts commit 3dfaf826.

Reason for revert: Failures - https://ci.chromium.org/p/v8/builders/luci.v8.ci/V8%20Linux%20gcc%204.8/20394

Original change's description:
> [debug] liveedit in native
> 
> Liveedit step-by-step:
> 1. calculate diff between old source and new source,
> 2. map function literals from old source to new source,
> 3. create new script for new_source,
> 4. mark literals with changed code as changed, all others as unchanged,
> 5. check that for changed literals there are no:
>   - running generators in the heap,
>   - non droppable frames (e.g. running generator) above them on stack.
> 6. mark the bottom most frame with changed function as scheduled for
>    restart if any.
> 7. for unchanged functions:
>   - deoptimize,
>   - remove from cache,
>   - update source positions,
>   - move to new script,
>   - reset feedback information and preparsed scope information if any,
>   - replace any sfi in constant pool with changed one if any.
> 8. for changed functions:
>   - deoptimize
>   - remove from cache,
>   - reset feedback information,
>   - update all links from js functions to old shared with new one.
> 9. swap scripts.
> 
> TBR=ulan@chromium.org
> 
> Bug: v8:7862,v8:5713
> Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
> Change-Id: I8f6f6156318cc82d6f36d7ebc1c9f7d5f3aa1461
> Reviewed-on: https://chromium-review.googlesource.com/1105493
> Reviewed-by: Aleksey Kozyatinskiy <kozyatinskiy@chromium.org>
> Reviewed-by: Dmitry Gozman <dgozman@chromium.org>
> Reviewed-by: Yang Guo <yangguo@chromium.org>
> Commit-Queue: Aleksey Kozyatinskiy <kozyatinskiy@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#54146}

TBR=dgozman@chromium.org,ulan@chromium.org,yangguo@chromium.org,kozyatinskiy@chromium.org

Change-Id: I45df5b6f3abaf29e593c6ac11edefbd0177d0109
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7862, v8:5713
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Reviewed-on: https://chromium-review.googlesource.com/1124159Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54151}
parent 93f59dee
...@@ -661,6 +661,7 @@ action("js2c") { ...@@ -661,6 +661,7 @@ action("js2c") {
"src/js/prologue.js", "src/js/prologue.js",
"src/js/array.js", "src/js/array.js",
"src/js/typedarray.js", "src/js/typedarray.js",
"src/debug/liveedit.js",
] ]
outputs = [ outputs = [
...@@ -2288,6 +2289,7 @@ v8_source_set("v8_base") { ...@@ -2288,6 +2289,7 @@ v8_source_set("v8_base") {
"src/runtime/runtime-interpreter.cc", "src/runtime/runtime-interpreter.cc",
"src/runtime/runtime-intl.cc", "src/runtime/runtime-intl.cc",
"src/runtime/runtime-literals.cc", "src/runtime/runtime-literals.cc",
"src/runtime/runtime-liveedit.cc",
"src/runtime/runtime-maths.cc", "src/runtime/runtime-maths.cc",
"src/runtime/runtime-module.cc", "src/runtime/runtime-module.cc",
"src/runtime/runtime-numbers.cc", "src/runtime/runtime-numbers.cc",
......
...@@ -1204,9 +1204,37 @@ bool Compiler::CompileOptimized(Handle<JSFunction> function, ...@@ -1204,9 +1204,37 @@ bool Compiler::CompileOptimized(Handle<JSFunction> function,
return true; return true;
} }
MaybeHandle<SharedFunctionInfo> Compiler::CompileForLiveEdit( MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) {
ParseInfo* parse_info, Isolate* isolate) { Isolate* isolate = script->GetIsolate();
return CompileToplevel(parse_info, isolate); DCHECK(AllowCompilation::IsAllowed(isolate));
// In order to ensure that live edit function info collection finds the newly
// generated shared function infos, clear the script's list temporarily
// and restore it at the end of this method.
Handle<WeakFixedArray> old_function_infos(script->shared_function_infos(),
isolate);
script->set_shared_function_infos(isolate->heap()->empty_weak_fixed_array());
// Start a compilation.
ParseInfo parse_info(isolate, script);
parse_info.set_eager();
// TODO(635): support extensions.
Handle<JSArray> infos;
Handle<SharedFunctionInfo> shared_info;
if (CompileToplevel(&parse_info, isolate).ToHandle(&shared_info)) {
// Check postconditions on success.
DCHECK(!isolate->has_pending_exception());
infos = LiveEditFunctionTracker::Collect(parse_info.literal(), script,
parse_info.zone(), isolate);
}
// Restore the original function info list in order to remain side-effect
// free as much as possible, since some code expects the old shared function
// infos to stick around.
script->set_shared_function_infos(*old_function_infos);
return infos;
} }
MaybeHandle<JSFunction> Compiler::GetFunctionFromEval( MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
......
...@@ -57,9 +57,7 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic { ...@@ -57,9 +57,7 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
ClearExceptionFlag flag); ClearExceptionFlag flag);
static bool Compile(Handle<JSFunction> function, ClearExceptionFlag flag); static bool Compile(Handle<JSFunction> function, ClearExceptionFlag flag);
static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode); static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode);
static MaybeHandle<JSArray> CompileForLiveEdit(Handle<Script> script);
V8_WARN_UNUSED_RESULT static MaybeHandle<SharedFunctionInfo>
CompileForLiveEdit(ParseInfo* parse_info, Isolate* isolate);
// Creates a new task that when run will parse and compile the streamed // Creates a new task that when run will parse and compile the streamed
// script associated with |streaming_data| and can be finalized with // script associated with |streaming_data| and can be finalized with
......
...@@ -79,8 +79,6 @@ void BreakRightNow(Isolate* isolate); ...@@ -79,8 +79,6 @@ void BreakRightNow(Isolate* isolate);
bool AllFramesOnStackAreBlackboxed(Isolate* isolate); bool AllFramesOnStackAreBlackboxed(Isolate* isolate);
class Script;
struct LiveEditResult { struct LiveEditResult {
enum Status { enum Status {
OK, OK,
...@@ -94,8 +92,6 @@ struct LiveEditResult { ...@@ -94,8 +92,6 @@ struct LiveEditResult {
}; };
Status status = OK; Status status = OK;
bool stack_changed = false; bool stack_changed = false;
// Available only for OK.
v8::Local<v8::debug::Script> script;
// Fields below are available only for COMPILE_ERROR. // Fields below are available only for COMPILE_ERROR.
v8::Local<v8::String> message; v8::Local<v8::String> message;
int line_number = -1; int line_number = -1;
......
...@@ -1910,12 +1910,62 @@ bool Debug::CanBreakAtEntry(Handle<SharedFunctionInfo> shared) { ...@@ -1910,12 +1910,62 @@ bool Debug::CanBreakAtEntry(Handle<SharedFunctionInfo> shared) {
} }
bool Debug::SetScriptSource(Handle<Script> script, Handle<String> source, bool Debug::SetScriptSource(Handle<Script> script, Handle<String> source,
bool preview, debug::LiveEditResult* result) { bool preview, debug::LiveEditResult* output) {
SaveContext save(isolate_);
StackFrame::Id frame_id = break_frame_id();
DebugScope debug_scope(this); DebugScope debug_scope(this);
if (debug_scope.failed()) return false;
isolate_->set_context(*debug_context());
if (frame_id != StackFrame::NO_ID) {
thread_local_.break_frame_id_ = frame_id;
}
Handle<Object> script_wrapper = Script::GetWrapper(script);
Handle<Object> argv[] = {script_wrapper, source,
isolate_->factory()->ToBoolean(preview),
isolate_->factory()->NewJSArray(0)};
Handle<Object> result;
MaybeHandle<Object> maybe_exception;
running_live_edit_ = true; running_live_edit_ = true;
LiveEdit::PatchScript(isolate_, script, source, preview, result); if (!CallFunction("SetScriptSource", arraysize(argv), argv, &maybe_exception)
.ToHandle(&result)) {
Handle<Object> pending_exception = maybe_exception.ToHandleChecked();
if (pending_exception->IsJSObject()) {
Handle<JSObject> exception = Handle<JSObject>::cast(pending_exception);
Handle<String> message = Handle<String>::cast(
JSReceiver::GetProperty(isolate_, exception, "message")
.ToHandleChecked());
Handle<String> blocked_message =
isolate_->factory()->NewStringFromAsciiChecked(
"Blocked by functions on stack");
if (blocked_message->Equals(*message)) {
output->status = debug::LiveEditResult::
BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME;
} else {
Handle<JSObject> details = Handle<JSObject>::cast(
JSReceiver::GetProperty(isolate_, exception, "details")
.ToHandleChecked());
Handle<String> error = Handle<String>::cast(
JSReceiver::GetProperty(isolate_, details, "syntaxErrorMessage")
.ToHandleChecked());
output->status = debug::LiveEditResult::COMPILE_ERROR;
output->line_number = kNoSourcePosition;
output->column_number = kNoSourcePosition;
output->message = Utils::ToLocal(error);
}
}
running_live_edit_ = false;
return false;
}
Handle<Object> stack_changed_value =
JSReceiver::GetProperty(isolate_, Handle<JSObject>::cast(result),
"stack_modified")
.ToHandleChecked();
output->stack_changed = stack_changed_value->IsTrue(isolate_);
output->status = debug::LiveEditResult::OK;
running_live_edit_ = false; running_live_edit_ = false;
return result->status == debug::LiveEditResult::OK; return true;
} }
void Debug::OnCompileError(Handle<Script> script) { void Debug::OnCompileError(Handle<Script> script) {
...@@ -1927,9 +1977,6 @@ void Debug::OnAfterCompile(Handle<Script> script) { ...@@ -1927,9 +1977,6 @@ void Debug::OnAfterCompile(Handle<Script> script) {
} }
void Debug::ProcessCompileEvent(bool has_compile_error, Handle<Script> script) { void Debug::ProcessCompileEvent(bool has_compile_error, Handle<Script> script) {
// TODO(kozyatinskiy): teach devtools to work with liveedit scripts better
// first and then remove this fast return.
if (running_live_edit_) return;
// Attach the correct debug id to the script. The debug id is used by the // Attach the correct debug id to the script. The debug id is used by the
// inspector to filter scripts by native context. // inspector to filter scripts by native context.
script->set_context_data(isolate_->native_context()->debug_context_id()); script->set_context_data(isolate_->native_context()->debug_context_id());
...@@ -1949,6 +1996,7 @@ void Debug::ProcessCompileEvent(bool has_compile_error, Handle<Script> script) { ...@@ -1949,6 +1996,7 @@ void Debug::ProcessCompileEvent(bool has_compile_error, Handle<Script> script) {
running_live_edit_, has_compile_error); running_live_edit_, has_compile_error);
} }
Handle<Context> Debug::GetDebugContext() { Handle<Context> Debug::GetDebugContext() {
if (!is_loaded()) return Handle<Context>(); if (!is_loaded()) return Handle<Context>();
DebugScope debug_scope(this); DebugScope debug_scope(this);
......
...@@ -396,8 +396,6 @@ class Debug { ...@@ -396,8 +396,6 @@ class Debug {
// source position for break points. // source position for break points.
static const int kBreakAtEntryPosition = 0; static const int kBreakAtEntryPosition = 0;
void RemoveBreakInfoAndMaybeFree(Handle<DebugInfo> debug_info);
private: private:
explicit Debug(Isolate* isolate); explicit Debug(Isolate* isolate);
~Debug(); ~Debug();
...@@ -476,6 +474,7 @@ class Debug { ...@@ -476,6 +474,7 @@ class Debug {
typedef std::function<void(Handle<DebugInfo>)> DebugInfoClearFunction; typedef std::function<void(Handle<DebugInfo>)> DebugInfoClearFunction;
void ClearAllDebugInfos(DebugInfoClearFunction clear_function); void ClearAllDebugInfos(DebugInfoClearFunction clear_function);
void RemoveBreakInfoAndMaybeFree(Handle<DebugInfo> debug_info);
void FindDebugInfo(Handle<DebugInfo> debug_info, DebugInfoListNode** prev, void FindDebugInfo(Handle<DebugInfo> debug_info, DebugInfoListNode** prev,
DebugInfoListNode** curr); DebugInfoListNode** curr);
void FreeDebugInfoListNode(DebugInfoListNode* prev, DebugInfoListNode* node); void FreeDebugInfoListNode(DebugInfoListNode* prev, DebugInfoListNode* node);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -2149,5 +2149,47 @@ InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* ...@@ -2149,5 +2149,47 @@ InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
} }
return entry; return entry;
} }
// -------------------------------------------------------------------------
#define DEFINE_WRAPPER(type, field) \
class field##_Wrapper : public ZoneObject { \
public: /* NOLINT */ \
field##_Wrapper(const field& original) : frame_(original) { \
} \
field frame_; \
};
STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)
#undef DEFINE_WRAPPER
static StackFrame* AllocateFrameCopy(StackFrame* frame, Zone* zone) {
#define FRAME_TYPE_CASE(type, field) \
case StackFrame::type: { \
field##_Wrapper* wrapper = \
new(zone) field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
return &wrapper->frame_; \
}
switch (frame->type()) {
STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
default: UNREACHABLE();
}
#undef FRAME_TYPE_CASE
return nullptr;
}
Vector<StackFrame*> CreateStackMap(Isolate* isolate, Zone* zone) {
ZoneVector<StackFrame*> frames(zone);
for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
StackFrame* frame = AllocateFrameCopy(it.frame(), zone);
frames.push_back(frame);
}
return Vector<StackFrame*>(frames.data(), frames.size());
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -1323,6 +1323,11 @@ class SafeStackFrameIterator: public StackFrameIteratorBase { ...@@ -1323,6 +1323,11 @@ class SafeStackFrameIterator: public StackFrameIteratorBase {
StackFrame::Type top_frame_type_; StackFrame::Type top_frame_type_;
ExternalCallbackScope* external_callback_scope_; ExternalCallbackScope* external_callback_scope_;
}; };
// Reads all frames on the current stack and copies them into the current
// zone memory.
Vector<StackFrame*> CreateStackMap(Isolate* isolate, Zone* zone);
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -1567,33 +1567,6 @@ Handle<Script> Factory::NewScriptWithId(Handle<String> source, int script_id, ...@@ -1567,33 +1567,6 @@ Handle<Script> Factory::NewScriptWithId(Handle<String> source, int script_id,
return script; return script;
} }
Handle<Script> Factory::CloneScript(Handle<Script> script) {
Heap* heap = isolate()->heap();
int script_id = isolate()->heap()->NextScriptId();
Handle<Script> new_script =
Handle<Script>::cast(NewStruct(SCRIPT_TYPE, TENURED));
new_script->set_source(script->source());
new_script->set_name(script->name());
new_script->set_id(script_id);
new_script->set_line_offset(script->line_offset());
new_script->set_column_offset(script->column_offset());
new_script->set_context_data(script->context_data());
new_script->set_type(script->type());
new_script->set_wrapper(script->wrapper());
new_script->set_line_ends(heap->undefined_value());
new_script->set_eval_from_shared_or_wrapped_arguments(
script->eval_from_shared_or_wrapped_arguments());
new_script->set_shared_function_infos(*empty_weak_fixed_array(),
SKIP_WRITE_BARRIER);
new_script->set_eval_from_position(script->eval_from_position());
new_script->set_flags(script->flags());
new_script->set_host_defined_options(script->host_defined_options());
heap->set_script_list(
*FixedArrayOfWeakCells::Add(isolate(), script_list(), new_script));
LOG(isolate(), ScriptEvent(Logger::ScriptEventType::kCreate, script_id));
return new_script;
}
Handle<CallableTask> Factory::NewCallableTask(Handle<JSReceiver> callable, Handle<CallableTask> Factory::NewCallableTask(Handle<JSReceiver> callable,
Handle<Context> context) { Handle<Context> context) {
DCHECK(callable->IsCallable()); DCHECK(callable->IsCallable());
......
...@@ -408,7 +408,6 @@ class V8_EXPORT_PRIVATE Factory { ...@@ -408,7 +408,6 @@ class V8_EXPORT_PRIVATE Factory {
PretenureFlag tenure = TENURED); PretenureFlag tenure = TENURED);
Handle<Script> NewScriptWithId(Handle<String> source, int script_id, Handle<Script> NewScriptWithId(Handle<String> source, int script_id,
PretenureFlag tenure = TENURED); PretenureFlag tenure = TENURED);
Handle<Script> CloneScript(Handle<Script> script);
Handle<BreakPointInfo> NewBreakPointInfo(int source_position); Handle<BreakPointInfo> NewBreakPointInfo(int source_position);
Handle<BreakPoint> NewBreakPoint(int id, Handle<String> condition); Handle<BreakPoint> NewBreakPoint(int id, Handle<String> condition);
......
...@@ -114,7 +114,37 @@ class ActualScript : public V8DebuggerScript { ...@@ -114,7 +114,37 @@ class ActualScript : public V8DebuggerScript {
: V8DebuggerScript(isolate, String16::fromInteger(script->Id()), : V8DebuggerScript(isolate, String16::fromInteger(script->Id()),
GetNameOrSourceUrl(script)), GetNameOrSourceUrl(script)),
m_isLiveEdit(isLiveEdit) { m_isLiveEdit(isLiveEdit) {
Initialize(script); v8::Local<v8::String> tmp;
if (script->SourceURL().ToLocal(&tmp)) m_sourceURL = toProtocolString(tmp);
if (script->SourceMappingURL().ToLocal(&tmp))
m_sourceMappingURL = toProtocolString(tmp);
m_startLine = script->LineOffset();
m_startColumn = script->ColumnOffset();
std::vector<int> lineEnds = script->LineEnds();
CHECK(lineEnds.size());
int source_length = lineEnds[lineEnds.size() - 1];
if (lineEnds.size()) {
m_endLine = static_cast<int>(lineEnds.size()) + m_startLine - 1;
if (lineEnds.size() > 1) {
m_endColumn = source_length - lineEnds[lineEnds.size() - 2] - 1;
} else {
m_endColumn = source_length + m_startColumn;
}
} else {
m_endLine = m_startLine;
m_endColumn = m_startColumn;
}
USE(script->ContextId().To(&m_executionContextId));
if (script->Source().ToLocal(&tmp)) {
m_source = toProtocolString(tmp);
}
m_isModule = script->IsModule();
m_script.Reset(m_isolate, script);
m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel);
} }
bool isLiveEdit() const override { return m_isLiveEdit; } bool isLiveEdit() const override { return m_isLiveEdit; }
...@@ -145,8 +175,8 @@ class ActualScript : public V8DebuggerScript { ...@@ -145,8 +175,8 @@ class ActualScript : public V8DebuggerScript {
return; return;
} }
if (preview) return; if (preview) return;
m_source = newSource;
m_hash = String16(); m_hash = String16();
Initialize(scope.Escape(result->script));
} }
bool getPossibleBreakpoints( bool getPossibleBreakpoints(
...@@ -229,40 +259,6 @@ class ActualScript : public V8DebuggerScript { ...@@ -229,40 +259,6 @@ class ActualScript : public V8DebuggerScript {
return m_script.Get(m_isolate); return m_script.Get(m_isolate);
} }
void Initialize(v8::Local<v8::debug::Script> script) {
v8::Local<v8::String> tmp;
if (script->SourceURL().ToLocal(&tmp)) m_sourceURL = toProtocolString(tmp);
if (script->SourceMappingURL().ToLocal(&tmp))
m_sourceMappingURL = toProtocolString(tmp);
m_startLine = script->LineOffset();
m_startColumn = script->ColumnOffset();
std::vector<int> lineEnds = script->LineEnds();
CHECK(lineEnds.size());
int source_length = lineEnds[lineEnds.size() - 1];
if (lineEnds.size()) {
m_endLine = static_cast<int>(lineEnds.size()) + m_startLine - 1;
if (lineEnds.size() > 1) {
m_endColumn = source_length - lineEnds[lineEnds.size() - 2] - 1;
} else {
m_endColumn = source_length + m_startColumn;
}
} else {
m_endLine = m_startLine;
m_endColumn = m_startColumn;
}
USE(script->ContextId().To(&m_executionContextId));
if (script->Source().ToLocal(&tmp)) {
m_source = toProtocolString(tmp);
}
m_isModule = script->IsModule();
m_script.Reset(m_isolate, script);
m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel);
}
String16 m_sourceMappingURL; String16 m_sourceMappingURL;
bool m_isLiveEdit = false; bool m_isLiveEdit = false;
bool m_isModule = false; bool m_isModule = false;
......
...@@ -899,7 +899,7 @@ RUNTIME_FUNCTION(Runtime_LiveEditPatchScript) { ...@@ -899,7 +899,7 @@ RUNTIME_FUNCTION(Runtime_LiveEditPatchScript) {
Handle<Script> script(Script::cast(script_function->shared()->script()), Handle<Script> script(Script::cast(script_function->shared()->script()),
isolate); isolate);
v8::debug::LiveEditResult result; v8::debug::LiveEditResult result;
LiveEdit::PatchScript(isolate, script, new_source, false, &result); LiveEdit::PatchScript(script, new_source, &result);
switch (result.status) { switch (result.status) {
case v8::debug::LiveEditResult::COMPILE_ERROR: case v8::debug::LiveEditResult::COMPILE_ERROR:
return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked( return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
......
...@@ -287,6 +287,19 @@ namespace internal { ...@@ -287,6 +287,19 @@ namespace internal {
F(CreateObjectLiteral, 4, 1) \ F(CreateObjectLiteral, 4, 1) \
F(CreateRegExpLiteral, 4, 1) F(CreateRegExpLiteral, 4, 1)
#define FOR_EACH_INTRINSIC_LIVEEDIT(F) \
F(LiveEditCheckAndDropActivations, 3, 1) \
F(LiveEditCompareStrings, 2, 1) \
F(LiveEditFindSharedFunctionInfosForScript, 1, 1) \
F(LiveEditFixupScript, 2, 1) \
F(LiveEditFunctionSetScript, 2, 1) \
F(LiveEditFunctionSourceUpdated, 2, 1) \
F(LiveEditGatherCompileInfo, 2, 1) \
F(LiveEditPatchFunctionPositions, 2, 1) \
F(LiveEditReplaceFunctionCode, 2, 1) \
F(LiveEditReplaceRefToNestedFunction, 3, 1) \
F(LiveEditReplaceScript, 3, 1)
#define FOR_EACH_INTRINSIC_MATHS(F) F(GenerateRandomNumbers, 0, 1) #define FOR_EACH_INTRINSIC_MATHS(F) F(GenerateRandomNumbers, 0, 1)
#define FOR_EACH_INTRINSIC_MODULE(F) \ #define FOR_EACH_INTRINSIC_MODULE(F) \
...@@ -611,6 +624,7 @@ namespace internal { ...@@ -611,6 +624,7 @@ namespace internal {
FOR_EACH_INTRINSIC_INTERPRETER(F) \ FOR_EACH_INTRINSIC_INTERPRETER(F) \
FOR_EACH_INTRINSIC_INTL(F) \ FOR_EACH_INTRINSIC_INTL(F) \
FOR_EACH_INTRINSIC_LITERALS(F) \ FOR_EACH_INTRINSIC_LITERALS(F) \
FOR_EACH_INTRINSIC_LIVEEDIT(F) \
FOR_EACH_INTRINSIC_MATHS(F) \ FOR_EACH_INTRINSIC_MATHS(F) \
FOR_EACH_INTRINSIC_MODULE(F) \ FOR_EACH_INTRINSIC_MODULE(F) \
FOR_EACH_INTRINSIC_NUMBERS(F) \ FOR_EACH_INTRINSIC_NUMBERS(F) \
......
...@@ -203,7 +203,7 @@ void PatchFunctions(v8::Local<v8::Context> context, const char* source_a, ...@@ -203,7 +203,7 @@ void PatchFunctions(v8::Local<v8::Context> context, const char* source_a,
v8::debug::LiveEditResult* result = nullptr) { v8::debug::LiveEditResult* result = nullptr) {
v8::Isolate* isolate = context->GetIsolate(); v8::Isolate* isolate = context->GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
v8::EscapableHandleScope scope(isolate); v8::HandleScope scope(isolate);
v8::Local<v8::Script> script_a = v8::Local<v8::Script> script_a =
v8::Script::Compile(context, v8_str(isolate, source_a)).ToLocalChecked(); v8::Script::Compile(context, v8_str(isolate, source_a)).ToLocalChecked();
script_a->Run(context).ToLocalChecked(); script_a->Run(context).ToLocalChecked();
...@@ -213,24 +213,20 @@ void PatchFunctions(v8::Local<v8::Context> context, const char* source_a, ...@@ -213,24 +213,20 @@ void PatchFunctions(v8::Local<v8::Context> context, const char* source_a,
if (result) { if (result) {
LiveEdit::PatchScript( LiveEdit::PatchScript(
i_isolate, i_script_a, i_script_a, i_isolate->factory()->NewStringFromAsciiChecked(source_b),
i_isolate->factory()->NewStringFromAsciiChecked(source_b), false,
result); result);
if (result->status == v8::debug::LiveEditResult::COMPILE_ERROR) {
result->message = scope.Escape(result->message);
}
} else { } else {
v8::debug::LiveEditResult result; v8::debug::LiveEditResult result;
LiveEdit::PatchScript( LiveEdit::PatchScript(
i_isolate, i_script_a, i_script_a, i_isolate->factory()->NewStringFromAsciiChecked(source_b),
i_isolate->factory()->NewStringFromAsciiChecked(source_b), false,
&result); &result);
CHECK_EQ(result.status, v8::debug::LiveEditResult::OK); CHECK_EQ(result.status, v8::debug::LiveEditResult::OK);
} }
} }
} // anonymous namespace } // anonymous namespace
TEST(LiveEditPatchFunctions) { // TODO(kozyatinskiy): enable it with new liveedit implementation.
DISABLED_TEST(LiveEditPatchFunctions) {
LocalContext env; LocalContext env;
v8::HandleScope scope(env->GetIsolate()); v8::HandleScope scope(env->GetIsolate());
v8::Local<v8::Context> context = env.local(); v8::Local<v8::Context> context = env.local();
...@@ -371,6 +367,7 @@ TEST(LiveEditPatchFunctions) { ...@@ -371,6 +367,7 @@ TEST(LiveEditPatchFunctions) {
->ToInt32(env->GetIsolate()) ->ToInt32(env->GetIsolate())
->Value(), ->Value(),
20); 20);
// Change inner functions. // Change inner functions.
PatchFunctions( PatchFunctions(
context, context,
...@@ -420,53 +417,10 @@ TEST(LiveEditPatchFunctions) { ...@@ -420,53 +417,10 @@ TEST(LiveEditPatchFunctions) {
v8::String::Utf8Value new_result_utf8(env->GetIsolate(), result); v8::String::Utf8Value new_result_utf8(env->GetIsolate(), result);
CHECK_NOT_NULL(strstr(*new_result_utf8, "cb")); CHECK_NOT_NULL(strstr(*new_result_utf8, "cb"));
} }
// TODO(kozyatinskiy): should work when we remove (.
PatchFunctions(context, "f = () => 2", "f = a => a");
CHECK_EQ(CompileRunChecked(env->GetIsolate(), "f(3)")
->ToInt32(env->GetIsolate())
->Value(),
2);
// Replace function with not a function.
PatchFunctions(context, "f = () => 2", "f = a == 2");
CHECK_EQ(CompileRunChecked(env->GetIsolate(), "f(3)")
->ToInt32(env->GetIsolate())
->Value(),
2);
// TODO(kozyatinskiy): should work when we put function into (...).
PatchFunctions(context, "f = a => 2", "f = (a => 5)()");
CHECK_EQ(CompileRunChecked(env->GetIsolate(), "f()")
->ToInt32(env->GetIsolate())
->Value(),
2);
PatchFunctions(context,
"f2 = null;\n"
"f = () => {\n"
" f2 = () => 5;\n"
" return f2();\n"
"}\n"
"f()\n",
"f2 = null;\n"
"f = () => {\n"
" for (var a = (() => 7)(), b = 0; a < 10; ++a,++b);\n"
" return b;\n"
"}\n"
"f()\n");
// TODO(kozyatinskiy): ditto.
CHECK_EQ(CompileRunChecked(env->GetIsolate(), "f2()")
->ToInt32(env->GetIsolate())
->Value(),
5);
CHECK_EQ(CompileRunChecked(env->GetIsolate(), "f()")
->ToInt32(env->GetIsolate())
->Value(),
3);
} }
TEST(LiveEditCompileError) { // TODO(kozyatinskiy): enable it with new liveedit implementation.
DISABLED_TEST(LiveEditCompileError) {
LocalContext env; LocalContext env;
v8::HandleScope scope(env->GetIsolate()); v8::HandleScope scope(env->GetIsolate());
v8::Local<v8::Context> context = env.local(); v8::Local<v8::Context> context = env.local();
...@@ -498,8 +452,10 @@ TEST(LiveEditCompileError) { ...@@ -498,8 +452,10 @@ TEST(LiveEditCompileError) {
PatchFunctions(context, "function foo() {}", PatchFunctions(context, "function foo() {}",
"function foo() { return a # b; }", &result); "function foo() { return a # b; }", &result);
CHECK_EQ(result.status, debug::LiveEditResult::COMPILE_ERROR); CHECK_EQ(result.status, debug::LiveEditResult::COMPILE_ERROR);
CHECK_EQ(result.line_number, 1); // TODO(kozyatinskiy): should be 1.
CHECK_EQ(result.column_number, 26); CHECK_EQ(result.line_number, kNoSourcePosition);
// TODO(kozyatinskiy): should be 26.
CHECK_EQ(result.column_number, kNoSourcePosition);
} }
TEST(LiveEditFunctionExpression) { TEST(LiveEditFunctionExpression) {
...@@ -526,8 +482,7 @@ TEST(LiveEditFunctionExpression) { ...@@ -526,8 +482,7 @@ TEST(LiveEditFunctionExpression) {
i_isolate); i_isolate);
debug::LiveEditResult result; debug::LiveEditResult result;
LiveEdit::PatchScript( LiveEdit::PatchScript(
i_isolate, i_script, i_script, i_isolate->factory()->NewStringFromAsciiChecked(updated_source),
i_isolate->factory()->NewStringFromAsciiChecked(updated_source), false,
&result); &result);
CHECK_EQ(result.status, debug::LiveEditResult::OK); CHECK_EQ(result.status, debug::LiveEditResult::OK);
{ {
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
Debug = debug.Debug;
function test(i) {
if (i == 3) {
return (function* gen() { yield test(i - 1); })().next().value;
} else if (i > 1) {
return test(i - 1);
} else {
debugger;
return 5;
}
}
let patch = null, exception = null;
Debug.setListener(listener);
patch = ['return 5', 'return 3'];
assertEquals(3, test(2)); // no running generator
patch = ['return 3', 'return -1'];
assertEquals(3, test(3)); // there is running generator
assertEquals(exception,
'LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME');
Debug.setListener(null);
function listener(event) {
if (event != Debug.DebugEvent.Break || !patch) return;
try {
%LiveEditPatchScript(test,
Debug.scriptSource(test).replace(patch[0], patch[1]));
} catch (e) {
exception = e;
}
patch = null;
}
...@@ -53,6 +53,7 @@ Debug.setListener(null); ...@@ -53,6 +53,7 @@ Debug.setListener(null);
assertNull(exception); assertNull(exception);
assertEquals(["Emacs", "Eclipse", "Vim"], results); assertEquals(["Emacs", "Eclipse", "Vim"], results);
// TODO(kozyatinskiy): uncomment lines with new liveedit implementation.
assertEquals([ assertEquals([
"debugger;", "debugger;",
"results.push(BestEditor());", "results.push(BestEditor());",
...@@ -61,12 +62,12 @@ assertEquals([ ...@@ -61,12 +62,12 @@ assertEquals([
"results.push(BestEditor());", "results.push(BestEditor());",
"results.push(BestEditor());", "results.push(BestEditor());",
" return 'Emacs';", " return 'Emacs';",
" return 'Eclipse';", // " return 'Eclipse';",
" return 'Eclipse';", " return 'Eclipse';",
"results.push(BestEditor());", "results.push(BestEditor());",
"results.push(BestEditor());", "results.push(BestEditor());",
" return 'Eclipse';", " return 'Eclipse';",
" return 'Vim';", // " return 'Vim';",
" return 'Vim';", " return 'Vim';",
"results.push(BestEditor());", "results.push(BestEditor());",
"Debug.setListener(null);" "Debug.setListener(null);"
......
...@@ -46,7 +46,8 @@ function Replace(fun, original, patch) { ...@@ -46,7 +46,8 @@ function Replace(fun, original, patch) {
try { try {
%LiveEditPatchScript(fun, Debug.scriptSource(fun).replace(original, patch)); %LiveEditPatchScript(fun, Debug.scriptSource(fun).replace(original, patch));
} catch (e) { } catch (e) {
assertEquals(e, 'LiveEdit failed: BLOCKED_BY_NEW_TARGET_IN_RESTART_FRAME'); // TODO(kozyatinskiy): message should be BLOCKED_BY_NEW_TARGET_IN_RESTART_FRAME.
assertEquals(e, 'LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME');
exceptions++; exceptions++;
} }
}); });
......
...@@ -43,7 +43,8 @@ function Replace(fun, original, patch) { ...@@ -43,7 +43,8 @@ function Replace(fun, original, patch) {
try { try {
%LiveEditPatchScript(fun, Debug.scriptSource(fun).replace(original, patch)); %LiveEditPatchScript(fun, Debug.scriptSource(fun).replace(original, patch));
} catch (e) { } catch (e) {
assertEquals(e, 'LiveEdit failed: BLOCKED_BY_NEW_TARGET_IN_RESTART_FRAME'); // TODO(kozyatinskiy): message should be BLOCKED_BY_NEW_TARGET_IN_RESTART_FRAME.
assertEquals(e, 'LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME');
exceptions++; exceptions++;
} }
}); });
......
...@@ -97,9 +97,10 @@ function patch(fun, from, to) { ...@@ -97,9 +97,10 @@ function patch(fun, from, to) {
// Patching will fail however when a live iterator is suspended. // Patching will fail however when a live iterator is suspended.
iter = generator(function(){}); iter = generator(function(){});
assertIteratorResult(undefined, false, iter.next()); assertIteratorResult(undefined, false, iter.next());
// TODO(kozyatinskiy): message should be BLOCKED_BY_RUNNING_GENERATOR.
assertThrowsEquals(function() { assertThrowsEquals(function() {
patch(generator, '\'Capybara\'', '\'Tapir\'') patch(generator, '\'Capybara\'', '\'Tapir\'')
}, 'LiveEdit failed: BLOCKED_BY_RUNNING_GENERATOR'); }, 'LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME');
assertIteratorResult("Capybara", true, iter.next()); assertIteratorResult("Capybara", true, iter.next());
// Try to patch functions with activations inside and outside generator // Try to patch functions with activations inside and outside generator
......
...@@ -106,9 +106,10 @@ function patch(fun, from, to) { ...@@ -106,9 +106,10 @@ function patch(fun, from, to) {
// Patching will fail however when an async function is suspended. // Patching will fail however when an async function is suspended.
var resolve; var resolve;
promise = asyncfn(function(){return new Promise(function(r){resolve = r})}); promise = asyncfn(function(){return new Promise(function(r){resolve = r})});
// TODO(kozyatinskiy): message should be BLOCKED_BY_RUNNING_GENERATOR.
assertThrowsEquals(function() { assertThrowsEquals(function() {
patch(asyncfn, '\'Capybara\'', '\'Tapir\'') patch(asyncfn, '\'Capybara\'', '\'Tapir\'')
}, 'LiveEdit failed: BLOCKED_BY_RUNNING_GENERATOR'); }, 'LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME');
resolve(); resolve();
assertPromiseValue("Capybara", promise); assertPromiseValue("Capybara", promise);
......
Breakpoint in liveedited script
Update script source
{
callFrames : [
]
stackChanged : false
}
Set breakpoint
{
actualLocation : {
columnNumber : 0
lineNumber : 3
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
Call function foo and dump stack
foo (:3:0)
(anonymous) (:0:0)
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
let {session, contextGroup, Protocol} =
InspectorTest.start('Breakpoint in liveedited script');
contextGroup.addScript(
`function foo() {
}
var f = foo;`);
const newSource = `function boo() {
}
function foo() {
}
f = foo;`;
(async function test() {
session.setupScriptMap();
Protocol.Debugger.enable();
const {params: {scriptId}} = await Protocol.Debugger.onceScriptParsed();
InspectorTest.log('Update script source');
let {result} = await Protocol.Debugger.setScriptSource(
{scriptId, scriptSource: newSource})
InspectorTest.logMessage(result);
InspectorTest.log('Set breakpoint');
({result} = await Protocol.Debugger.setBreakpoint({location:{
scriptId,
lineNumber: 3,
columnNumber: 0
}}));
InspectorTest.logMessage(result);
InspectorTest.log('Call function foo and dump stack');
Protocol.Runtime.evaluate({expression: 'foo()'});
const {params:{callFrames}} = await Protocol.Debugger.oncePaused();
session.logCallFrames(callFrames);
InspectorTest.completeTest();
})();
...@@ -14,10 +14,10 @@ Running test: testSourceWithSyntaxError ...@@ -14,10 +14,10 @@ Running test: testSourceWithSyntaxError
id : <messageId> id : <messageId>
result : { result : {
exceptionDetails : { exceptionDetails : {
columnNumber : 11 columnNumber : 0
exceptionId : <exceptionId> exceptionId : <exceptionId>
lineNumber : 1 lineNumber : 0
text : Uncaught SyntaxError: Invalid or unexpected token text : Invalid or unexpected token
} }
} }
} }
...@@ -10,10 +10,10 @@ TestExpression(2,4) === 8 ...@@ -10,10 +10,10 @@ TestExpression(2,4) === 8
Update current script source 'a * b' -> 'a # b'.. Update current script source 'a * b' -> 'a # b'..
{ {
exceptionDetails : { exceptionDetails : {
columnNumber : 13 columnNumber : 0
exceptionId : <exceptionId> exceptionId : <exceptionId>
lineNumber : 1 lineNumber : 0
text : Uncaught SyntaxError: Invalid or unexpected token text : Invalid or unexpected token
} }
} }
TestExpression(2,4) === 8 TestExpression(2,4) === 8
...@@ -297,7 +297,7 @@ class SourceProcessor(SourceFileProcessor): ...@@ -297,7 +297,7 @@ class SourceProcessor(SourceFileProcessor):
m = pattern.match(line) m = pattern.match(line)
if m: if m:
runtime_functions.append(m.group(1)) runtime_functions.append(m.group(1))
if len(runtime_functions) < 450: if len(runtime_functions) < 475:
print ("Runtime functions list is suspiciously short. " print ("Runtime functions list is suspiciously short. "
"Consider updating the presubmit script.") "Consider updating the presubmit script.")
sys.exit(1) sys.exit(1)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment