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/debug-evaluate.cc b/src/debug/debug-evaluate.cc
index 1729408..d5ebaa5 100644
--- a/src/debug/debug-evaluate.cc
+++ b/src/debug/debug-evaluate.cc
@@ -95,11 +95,12 @@
}
Handle<JSFunction> eval_fun;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, eval_fun,
- Compiler::GetFunctionFromEval(
- source, outer_info, context, SLOPPY,
- NO_PARSE_RESTRICTION, RelocInfo::kNoPosition),
- Object);
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, eval_fun,
+ Compiler::GetFunctionFromEval(
+ source, outer_info, context, SLOPPY, NO_PARSE_RESTRICTION,
+ RelocInfo::kNoPosition, RelocInfo::kNoPosition),
+ Object);
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
@@ -182,7 +183,8 @@
context_chain_element.wrapped_context = current_context;
}
context_chain_.Add(context_chain_element);
- } else if (scope_type == ScopeIterator::ScopeTypeBlock) {
+ } else if (scope_type == ScopeIterator::ScopeTypeBlock ||
+ scope_type == ScopeIterator::ScopeTypeEval) {
Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
frame_inspector.MaterializeStackLocals(materialized,
it.CurrentScopeInfo());
@@ -247,7 +249,8 @@
// 'this' is allocated in an outer context and is is already being
// referenced by the current function, so it can be correctly resolved.
return;
- } else if (local_function->shared()->scope_info()->HasReceiver()) {
+ } else if (local_function->shared()->scope_info()->HasReceiver() &&
+ !frame_->receiver()->IsTheHole()) {
recv = handle(frame_->receiver(), isolate_);
}
JSObject::SetOwnPropertyIgnoreAttributes(target, name, recv, NONE).Check();
diff --git a/src/debug/debug-frames.cc b/src/debug/debug-frames.cc
index a7956ff..453a77d 100644
--- a/src/debug/debug-frames.cc
+++ b/src/debug/debug-frames.cc
@@ -72,8 +72,7 @@
return deoptimized_frame_->GetSourcePosition();
} else if (is_interpreted_) {
InterpretedFrame* frame = reinterpret_cast<InterpretedFrame*>(frame_);
- BytecodeArray* bytecode_array =
- frame->function()->shared()->bytecode_array();
+ BytecodeArray* bytecode_array = frame->GetBytecodeArray();
return bytecode_array->SourcePosition(frame->GetBytecodeOffset());
} else {
Code* code = frame_->LookupCode();
@@ -117,6 +116,7 @@
// TODO(yangguo): check whether this is necessary, now that we materialize
// context locals as well.
Handle<String> name(scope_info->ParameterName(i));
+ if (ScopeInfo::VariableIsSynthetic(*name)) continue;
if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
Handle<Object> value =
@@ -130,8 +130,8 @@
// Second fill all stack locals.
for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
- if (scope_info->LocalIsSynthetic(i)) continue;
Handle<String> name(scope_info->StackLocalName(i));
+ if (ScopeInfo::VariableIsSynthetic(*name)) continue;
Handle<Object> value = GetExpression(scope_info->StackLocalIndex(i));
// TODO(yangguo): We convert optimized out values to {undefined} when they
// are passed to the debugger. Eventually we should handle them somehow.
@@ -163,6 +163,7 @@
for (int i = 0; i < scope_info->ParameterCount(); ++i) {
// Shadowed parameters were not materialized.
Handle<String> name(scope_info->ParameterName(i));
+ if (ScopeInfo::VariableIsSynthetic(*name)) continue;
if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
DCHECK(!frame_->GetParameter(i)->IsTheHole());
@@ -173,13 +174,12 @@
// Stack locals.
for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
- if (scope_info->LocalIsSynthetic(i)) continue;
+ Handle<String> name(scope_info->StackLocalName(i));
+ if (ScopeInfo::VariableIsSynthetic(*name)) continue;
int index = scope_info->StackLocalIndex(i);
if (frame_->GetExpression(index)->IsTheHole()) continue;
Handle<Object> value =
- Object::GetPropertyOrElement(
- target, handle(scope_info->StackLocalName(i), isolate_))
- .ToHandleChecked();
+ Object::GetPropertyOrElement(target, name).ToHandleChecked();
frame_->SetExpression(index, *value);
}
}
diff --git a/src/debug/debug-scopes.cc b/src/debug/debug-scopes.cc
index d9c615b..1602711 100644
--- a/src/debug/debug-scopes.cc
+++ b/src/debug/debug-scopes.cc
@@ -5,6 +5,7 @@
#include "src/debug/debug-scopes.h"
#include "src/ast/scopes.h"
+#include "src/compiler.h"
#include "src/debug/debug.h"
#include "src/frames-inl.h"
#include "src/globals.h"
@@ -80,34 +81,29 @@
}
// Reparse the code and analyze the scopes.
- Scope* scope = NULL;
// Check whether we are in global, eval or function code.
Zone zone(isolate->allocator());
+ base::SmartPointer<ParseInfo> info;
if (scope_info->scope_type() != FUNCTION_SCOPE) {
// Global or eval code.
Handle<Script> script(Script::cast(shared_info->script()));
- ParseInfo info(&zone, script);
+ info.Reset(new ParseInfo(&zone, script));
+ info->set_toplevel();
if (scope_info->scope_type() == SCRIPT_SCOPE) {
- info.set_global();
+ info->set_global();
} else {
DCHECK(scope_info->scope_type() == EVAL_SCOPE);
- info.set_eval();
- info.set_context(Handle<Context>(function->context()));
+ info->set_eval();
+ info->set_context(Handle<Context>(function->context()));
}
- if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
- scope = info.literal()->scope();
- }
- if (!ignore_nested_scopes) RetrieveScopeChain(scope);
- if (collect_non_locals) CollectNonLocals(scope);
} else {
- // Function code
- ParseInfo info(&zone, function);
- if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
- scope = info.literal()->scope();
- }
- if (!ignore_nested_scopes) RetrieveScopeChain(scope);
- if (collect_non_locals) CollectNonLocals(scope);
+ // Inner function.
+ info.Reset(new ParseInfo(&zone, function));
}
+ Scope* scope = NULL;
+ if (Compiler::ParseAndAnalyze(info.get())) scope = info->literal()->scope();
+ if (!ignore_nested_scopes) RetrieveScopeChain(scope);
+ if (collect_non_locals) CollectNonLocals(scope);
UnwrapEvaluationContext();
}
@@ -126,8 +122,6 @@
while (true) {
if (context_.is_null()) return;
if (!context_->IsDebugEvaluateContext()) return;
- // An existing debug-evaluate context can only be outside the local scope.
- DCHECK(nested_scope_chain_.is_empty());
Handle<Object> wrapped(context_->get(Context::WRAPPED_CONTEXT_INDEX),
isolate_);
if (wrapped->IsContext()) {
@@ -201,11 +195,15 @@
} else if (nested_scope_chain_.is_empty()) {
context_ = Handle<Context>(context_->previous(), isolate_);
} else {
- if (nested_scope_chain_.last().scope_info->HasContext()) {
- DCHECK(context_->previous() != NULL);
- context_ = Handle<Context>(context_->previous(), isolate_);
- }
- nested_scope_chain_.RemoveLast();
+ do {
+ if (nested_scope_chain_.last().scope_info->HasContext()) {
+ DCHECK(context_->previous() != NULL);
+ context_ = Handle<Context>(context_->previous(), isolate_);
+ }
+ nested_scope_chain_.RemoveLast();
+ if (nested_scope_chain_.is_empty()) break;
+ // Repeat to skip hidden scopes.
+ } while (nested_scope_chain_.last().is_hidden());
}
UnwrapEvaluationContext();
}
@@ -236,8 +234,10 @@
DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
return ScopeTypeBlock;
case EVAL_SCOPE:
- UNREACHABLE();
+ DCHECK(!scope_info->HasContext() || context_->IsFunctionContext());
+ return ScopeTypeEval;
}
+ UNREACHABLE();
}
if (context_->IsNativeContext()) {
DCHECK(context_->global_object()->IsJSGlobalObject());
@@ -284,7 +284,8 @@
// Materialize the content of the closure scope into a JSObject.
return MaterializeClosure();
case ScopeIterator::ScopeTypeBlock:
- return MaterializeBlockScope();
+ case ScopeIterator::ScopeTypeEval:
+ return MaterializeInnerScope();
case ScopeIterator::ScopeTypeModule:
return MaterializeModuleScope();
}
@@ -295,7 +296,8 @@
bool ScopeIterator::HasContext() {
ScopeType type = Type();
- if (type == ScopeTypeBlock || type == ScopeTypeLocal) {
+ if (type == ScopeTypeBlock || type == ScopeTypeLocal ||
+ type == ScopeTypeEval) {
if (!nested_scope_chain_.is_empty()) {
return nested_scope_chain_.last().scope_info->HasContext();
}
@@ -321,7 +323,8 @@
case ScopeIterator::ScopeTypeScript:
return SetScriptVariableValue(variable_name, new_value);
case ScopeIterator::ScopeTypeBlock:
- return SetBlockVariableValue(variable_name, new_value);
+ case ScopeIterator::ScopeTypeEval:
+ return SetInnerScopeVariableValue(variable_name, new_value);
case ScopeIterator::ScopeTypeModule:
// TODO(2399): should we implement it?
break;
@@ -453,7 +456,7 @@
global->native_context()->script_context_table());
Handle<JSObject> script_scope =
- isolate_->factory()->NewJSObject(isolate_->object_function());
+ isolate_->factory()->NewJSObjectWithNullProto();
for (int context_index = 0; context_index < script_contexts->used();
context_index++) {
@@ -470,7 +473,7 @@
Handle<JSFunction> function = GetFunction();
Handle<JSObject> local_scope =
- isolate_->factory()->NewJSObject(isolate_->object_function());
+ isolate_->factory()->NewJSObjectWithNullProto();
frame_inspector_->MaterializeStackLocals(local_scope, function);
Handle<Context> frame_context =
@@ -482,19 +485,16 @@
if (!scope_info->HasContext()) return local_scope;
- // Third fill all context locals.
+ // Fill all context locals.
Handle<Context> function_context(frame_context->closure_context());
CopyContextLocalsToScopeObject(scope_info, function_context, local_scope);
// Finally copy any properties from the function context extension.
// These will be variables introduced by eval.
if (function_context->closure() == *function &&
- function_context->has_extension() &&
!function_context->IsNativeContext()) {
- bool success = CopyContextExtensionToScopeObject(
- handle(function_context->extension_object(), isolate_), local_scope,
- INCLUDE_PROTOS);
- if (!success) return MaybeHandle<JSObject>();
+ CopyContextExtensionToScopeObject(function_context, local_scope,
+ INCLUDE_PROTOS);
}
return local_scope;
@@ -513,19 +513,14 @@
// Allocate and initialize a JSObject with all the content of this function
// closure.
Handle<JSObject> closure_scope =
- isolate_->factory()->NewJSObject(isolate_->object_function());
+ isolate_->factory()->NewJSObjectWithNullProto();
// Fill all context locals to the context extension.
CopyContextLocalsToScopeObject(scope_info, context, closure_scope);
// Finally copy any properties from the function context extension. This will
// be variables introduced by eval.
- if (context->has_extension()) {
- bool success = CopyContextExtensionToScopeObject(
- handle(context->extension_object(), isolate_), closure_scope, OWN_ONLY);
- DCHECK(success);
- USE(success);
- }
+ CopyContextExtensionToScopeObject(context, closure_scope, OWN_ONLY);
return closure_scope;
}
@@ -540,7 +535,7 @@
Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
isolate_);
Handle<JSObject> catch_scope =
- isolate_->factory()->NewJSObject(isolate_->object_function());
+ isolate_->factory()->NewJSObjectWithNullProto();
JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object,
NONE)
.Check();
@@ -560,14 +555,14 @@
// Create a plain JSObject which materializes the block scope for the specified
// block context.
-Handle<JSObject> ScopeIterator::MaterializeBlockScope() {
- Handle<JSObject> block_scope =
- isolate_->factory()->NewJSObject(isolate_->object_function());
+Handle<JSObject> ScopeIterator::MaterializeInnerScope() {
+ Handle<JSObject> inner_scope =
+ isolate_->factory()->NewJSObjectWithNullProto();
Handle<Context> context = Handle<Context>::null();
if (!nested_scope_chain_.is_empty()) {
Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
- frame_inspector_->MaterializeStackLocals(block_scope, scope_info);
+ frame_inspector_->MaterializeStackLocals(inner_scope, scope_info);
if (scope_info->HasContext()) context = CurrentContext();
} else {
context = CurrentContext();
@@ -575,17 +570,10 @@
if (!context.is_null()) {
// Fill all context locals.
- CopyContextLocalsToScopeObject(handle(context->scope_info()),
- context, block_scope);
- // Fill all extension variables.
- if (context->extension_object() != nullptr) {
- bool success = CopyContextExtensionToScopeObject(
- handle(context->extension_object()), block_scope, OWN_ONLY);
- DCHECK(success);
- USE(success);
- }
+ CopyContextLocalsToScopeObject(CurrentScopeInfo(), context, inner_scope);
+ CopyContextExtensionToScopeObject(context, inner_scope, OWN_ONLY);
}
- return block_scope;
+ return inner_scope;
}
@@ -599,7 +587,7 @@
// Allocate and initialize a JSObject with all the members of the debugged
// module.
Handle<JSObject> module_scope =
- isolate_->factory()->NewJSObject(isolate_->object_function());
+ isolate_->factory()->NewJSObjectWithNullProto();
// Fill all context locals.
CopyContextLocalsToScopeObject(scope_info, context, module_scope);
@@ -607,12 +595,43 @@
return module_scope;
}
+bool ScopeIterator::SetParameterValue(Handle<ScopeInfo> scope_info,
+ JavaScriptFrame* frame,
+ Handle<String> parameter_name,
+ Handle<Object> new_value) {
+ // Setting stack locals of optimized frames is not supported.
+ if (frame->is_optimized()) return false;
+ HandleScope scope(isolate_);
+ for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+ if (String::Equals(handle(scope_info->ParameterName(i)), parameter_name)) {
+ frame->SetParameterValue(i, *new_value);
+ return true;
+ }
+ }
+ return false;
+}
-// Set the context local variable value.
-bool ScopeIterator::SetContextLocalValue(Handle<ScopeInfo> scope_info,
- Handle<Context> context,
- Handle<String> variable_name,
- Handle<Object> new_value) {
+bool ScopeIterator::SetStackVariableValue(Handle<ScopeInfo> scope_info,
+ JavaScriptFrame* frame,
+ Handle<String> variable_name,
+ Handle<Object> new_value) {
+ // Setting stack locals of optimized frames is not supported.
+ if (frame->is_optimized()) return false;
+ HandleScope scope(isolate_);
+ for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+ if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
+ frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ScopeIterator::SetContextVariableValue(Handle<ScopeInfo> scope_info,
+ Handle<Context> context,
+ Handle<String> variable_name,
+ Handle<Object> new_value) {
+ HandleScope scope(isolate_);
for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
Handle<String> next_name(scope_info->ContextLocalName(i));
if (String::Equals(variable_name, next_name)) {
@@ -626,128 +645,8 @@
}
}
- return false;
-}
-
-
-bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
- Handle<Object> new_value) {
- JavaScriptFrame* frame = GetFrame();
- // Optimized frames are not supported.
- if (frame->is_optimized()) return false;
-
- Handle<JSFunction> function(frame->function());
- Handle<SharedFunctionInfo> shared(function->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- bool default_result = false;
-
- // Parameters.
- for (int i = 0; i < scope_info->ParameterCount(); ++i) {
- HandleScope scope(isolate_);
- if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
- frame->SetParameterValue(i, *new_value);
- // Argument might be shadowed in heap context, don't stop here.
- default_result = true;
- }
- }
-
- // Stack locals.
- for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
- HandleScope scope(isolate_);
- if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
- frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
- return true;
- }
- }
-
- if (scope_info->HasContext()) {
- // Context locals.
- Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context(frame_context->declaration_context());
- if (SetContextLocalValue(scope_info, function_context, variable_name,
- new_value)) {
- return true;
- }
-
- // Function context extension. These are variables introduced by eval.
- if (function_context->closure() == *function) {
- if (function_context->has_extension() &&
- !function_context->IsNativeContext()) {
- Handle<JSObject> ext(function_context->extension_object());
-
- Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
- DCHECK(maybe.IsJust());
- if (maybe.FromJust()) {
- // We don't expect this to do anything except replacing
- // property value.
- Runtime::SetObjectProperty(isolate_, ext, variable_name, new_value,
- SLOPPY)
- .Assert();
- return true;
- }
- }
- }
- }
-
- return default_result;
-}
-
-
-bool ScopeIterator::SetBlockVariableValue(Handle<String> variable_name,
- Handle<Object> new_value) {
- Handle<ScopeInfo> scope_info = CurrentScopeInfo();
- JavaScriptFrame* frame = GetFrame();
-
- for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
- HandleScope scope(isolate_);
- if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
- frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
- return true;
- }
- }
-
- if (HasContext()) {
- Handle<Context> context = CurrentContext();
- if (SetContextLocalValue(scope_info, context, variable_name, new_value)) {
- return true;
- }
-
- Handle<JSObject> ext(context->extension_object(), isolate_);
- if (!ext.is_null()) {
- Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
- DCHECK(maybe.IsJust());
- if (maybe.FromJust()) {
- // We don't expect this to do anything except replacing property value.
- JSObject::SetOwnPropertyIgnoreAttributes(ext, variable_name, new_value,
- NONE)
- .Check();
- return true;
- }
- }
- }
-
- return false;
-}
-
-
-// This method copies structure of MaterializeClosure method above.
-bool ScopeIterator::SetClosureVariableValue(Handle<String> variable_name,
- Handle<Object> new_value) {
- Handle<Context> context = CurrentContext();
- DCHECK(context->IsFunctionContext());
-
- // Context locals to the context extension.
- Handle<SharedFunctionInfo> shared(context->closure()->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
- if (SetContextLocalValue(scope_info, context, variable_name, new_value)) {
- return true;
- }
-
- // Properties from the function context extension. This will
- // be variables introduced by eval.
if (context->has_extension()) {
- Handle<JSObject> ext(JSObject::cast(context->extension_object()));
+ Handle<JSObject> ext(context->extension_object());
Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
DCHECK(maybe.IsJust());
if (maybe.FromJust()) {
@@ -762,6 +661,55 @@
return false;
}
+bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
+ Handle<Object> new_value) {
+ JavaScriptFrame* frame = GetFrame();
+ Handle<ScopeInfo> scope_info(frame->function()->shared()->scope_info());
+
+ // Parameter might be shadowed in context. Don't stop here.
+ bool result = SetParameterValue(scope_info, frame, variable_name, new_value);
+
+ // Stack locals.
+ if (SetStackVariableValue(scope_info, frame, variable_name, new_value)) {
+ return true;
+ }
+
+ if (scope_info->HasContext() &&
+ SetContextVariableValue(scope_info, CurrentContext(), variable_name,
+ new_value)) {
+ return true;
+ }
+
+ return result;
+}
+
+bool ScopeIterator::SetInnerScopeVariableValue(Handle<String> variable_name,
+ Handle<Object> new_value) {
+ Handle<ScopeInfo> scope_info = CurrentScopeInfo();
+ DCHECK(scope_info->scope_type() == BLOCK_SCOPE ||
+ scope_info->scope_type() == EVAL_SCOPE);
+ JavaScriptFrame* frame = GetFrame();
+
+ // Setting stack locals of optimized frames is not supported.
+ if (SetStackVariableValue(scope_info, frame, variable_name, new_value)) {
+ return true;
+ }
+
+ if (HasContext() && SetContextVariableValue(scope_info, CurrentContext(),
+ variable_name, new_value)) {
+ return true;
+ }
+
+ return false;
+}
+
+// This method copies structure of MaterializeClosure method above.
+bool ScopeIterator::SetClosureVariableValue(Handle<String> variable_name,
+ Handle<Object> new_value) {
+ DCHECK(CurrentContext()->IsFunctionContext());
+ return SetContextVariableValue(CurrentScopeInfo(), CurrentContext(),
+ variable_name, new_value);
+}
bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name,
Handle<Object> new_value) {
@@ -780,7 +728,6 @@
return false;
}
-
bool ScopeIterator::SetCatchVariableValue(Handle<String> variable_name,
Handle<Object> new_value) {
Handle<Context> context = CurrentContext();
@@ -801,48 +748,47 @@
int local_count = scope_info->ContextLocalCount();
if (local_count == 0) return;
// Fill all context locals to the context extension.
- int first_context_var = scope_info->StackLocalCount();
- int start = scope_info->ContextLocalNameEntriesIndex();
for (int i = 0; i < local_count; ++i) {
- if (scope_info->LocalIsSynthetic(first_context_var + i)) continue;
+ Handle<String> name(scope_info->ContextLocalName(i));
+ if (ScopeInfo::VariableIsSynthetic(*name)) continue;
int context_index = Context::MIN_CONTEXT_SLOTS + i;
Handle<Object> value = Handle<Object>(context->get(context_index), isolate);
// Reflect variables under TDZ as undefined in scope object.
if (value->IsTheHole()) continue;
// This should always succeed.
// TODO(verwaest): Use AddDataProperty instead.
- JSObject::SetOwnPropertyIgnoreAttributes(
- scope_object, handle(String::cast(scope_info->get(i + start))), value,
- NONE)
+ JSObject::SetOwnPropertyIgnoreAttributes(scope_object, name, value, NONE)
.Check();
}
}
-bool ScopeIterator::CopyContextExtensionToScopeObject(
- Handle<JSObject> extension, Handle<JSObject> scope_object,
+void ScopeIterator::CopyContextExtensionToScopeObject(
+ Handle<Context> context, Handle<JSObject> scope_object,
KeyCollectionType type) {
- Handle<FixedArray> keys;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate_, keys, JSReceiver::GetKeys(extension, type, ENUMERABLE_STRINGS),
- false);
+ if (context->extension_object() == nullptr) return;
+ Handle<JSObject> extension(context->extension_object());
+ Handle<FixedArray> keys =
+ JSReceiver::GetKeys(extension, type, ENUMERABLE_STRINGS)
+ .ToHandleChecked();
for (int i = 0; i < keys->length(); i++) {
// Names of variables introduced by eval are strings.
DCHECK(keys->get(i)->IsString());
Handle<String> key(String::cast(keys->get(i)));
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate_, value, Object::GetPropertyOrElement(extension, key), false);
- RETURN_ON_EXCEPTION_VALUE(
- isolate_, JSObject::SetOwnPropertyIgnoreAttributes(
- scope_object, key, value, NONE), false);
+ Handle<Object> value =
+ Object::GetPropertyOrElement(extension, key).ToHandleChecked();
+ JSObject::SetOwnPropertyIgnoreAttributes(scope_object, key, value, NONE)
+ .Check();
}
- return true;
}
void ScopeIterator::GetNestedScopeChain(Isolate* isolate, Scope* scope,
int position) {
- if (!scope->is_eval_scope()) {
+ if (scope->is_hidden()) {
+ // We need to add this chain element in case the scope has a context
+ // associated. We need to keep the scope chain and context chain in sync.
+ nested_scope_chain_.Add(ExtendedScopeInfo(scope->GetScopeInfo(isolate)));
+ } else {
nested_scope_chain_.Add(ExtendedScopeInfo(scope->GetScopeInfo(isolate),
scope->start_position(),
scope->end_position()));
@@ -851,7 +797,7 @@
Scope* inner_scope = scope->inner_scopes()->at(i);
int beg_pos = inner_scope->start_position();
int end_pos = inner_scope->end_position();
- DCHECK(beg_pos >= 0 && end_pos >= 0);
+ DCHECK((beg_pos >= 0 && end_pos >= 0) || inner_scope->is_hidden());
if (beg_pos <= position && position < end_pos) {
GetNestedScopeChain(isolate, inner_scope, position);
return;
diff --git a/src/debug/debug-scopes.h b/src/debug/debug-scopes.h
index 4e95fc4..9560227 100644
--- a/src/debug/debug-scopes.h
+++ b/src/debug/debug-scopes.h
@@ -25,6 +25,7 @@
ScopeTypeCatch,
ScopeTypeBlock,
ScopeTypeScript,
+ ScopeTypeEval,
ScopeTypeModule
};
@@ -85,9 +86,12 @@
struct ExtendedScopeInfo {
ExtendedScopeInfo(Handle<ScopeInfo> info, int start, int end)
: scope_info(info), start_position(start), end_position(end) {}
+ explicit ExtendedScopeInfo(Handle<ScopeInfo> info)
+ : scope_info(info), start_position(-1), end_position(-1) {}
Handle<ScopeInfo> scope_info;
int start_position;
int end_position;
+ bool is_hidden() { return start_position == -1 && end_position == -1; }
};
Isolate* isolate_;
@@ -117,28 +121,37 @@
MUST_USE_RESULT MaybeHandle<JSObject> MaterializeModuleScope();
Handle<JSObject> MaterializeClosure();
Handle<JSObject> MaterializeCatchScope();
- Handle<JSObject> MaterializeBlockScope();
+ Handle<JSObject> MaterializeInnerScope();
Handle<JSObject> WithContextExtension();
bool SetLocalVariableValue(Handle<String> variable_name,
Handle<Object> new_value);
- bool SetBlockVariableValue(Handle<String> variable_name,
- Handle<Object> new_value);
+ bool SetInnerScopeVariableValue(Handle<String> variable_name,
+ Handle<Object> new_value);
bool SetClosureVariableValue(Handle<String> variable_name,
Handle<Object> new_value);
bool SetScriptVariableValue(Handle<String> variable_name,
Handle<Object> new_value);
bool SetCatchVariableValue(Handle<String> variable_name,
Handle<Object> new_value);
- bool SetContextLocalValue(Handle<ScopeInfo> scope_info,
- Handle<Context> context,
- Handle<String> variable_name,
- Handle<Object> new_value);
+
+ // Helper functions.
+ bool SetParameterValue(Handle<ScopeInfo> scope_info, JavaScriptFrame* frame,
+ Handle<String> parameter_name,
+ Handle<Object> new_value);
+ bool SetStackVariableValue(Handle<ScopeInfo> scope_info,
+ JavaScriptFrame* frame,
+ Handle<String> variable_name,
+ Handle<Object> new_value);
+ bool SetContextVariableValue(Handle<ScopeInfo> scope_info,
+ Handle<Context> context,
+ Handle<String> variable_name,
+ Handle<Object> new_value);
void CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
Handle<Context> context,
Handle<JSObject> scope_object);
- bool CopyContextExtensionToScopeObject(Handle<JSObject> extension,
+ void CopyContextExtensionToScopeObject(Handle<Context> context,
Handle<JSObject> scope_object,
KeyCollectionType type);
diff --git a/src/debug/debug.cc b/src/debug/debug.cc
index 6e94012..3b5fb5f 100644
--- a/src/debug/debug.cc
+++ b/src/debug/debug.cc
@@ -260,12 +260,6 @@
return it->GetBreakLocation();
}
-FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) {
- List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
- frame->Summarize(&frames);
- return frames.first();
-}
-
int CallOffsetFromCodeOffset(int code_offset, bool is_interpreted) {
// Code offset points to the instruction after the call. Subtract 1 to
// exclude that instruction from the search. For bytecode, the code offset
@@ -275,7 +269,7 @@
BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
JavaScriptFrame* frame) {
- FrameSummary summary = GetFirstFrameSummary(frame);
+ FrameSummary summary = FrameSummary::GetFirst(frame);
int call_offset =
CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted());
return FromCodeOffset(debug_info, call_offset);
@@ -631,7 +625,7 @@
step_break = location.IsTailCall();
// Fall through.
case StepIn: {
- FrameSummary summary = GetFirstFrameSummary(frame);
+ FrameSummary summary = FrameSummary::GetFirst(frame);
int offset = summary.code_offset();
step_break = step_break || location.IsReturn() ||
(current_fp != last_fp) ||
@@ -962,6 +956,14 @@
it.Advance();
}
+ if (last_step_action() == StepNext) {
+ while (!it.done()) {
+ Address current_fp = it.frame()->UnpaddedFP();
+ if (current_fp >= thread_local_.target_fp_) break;
+ it.Advance();
+ }
+ }
+
// Find the closest Javascript frame we can flood with one-shots.
while (!it.done() &&
!it.frame()->function()->shared()->IsSubjectToDebugging()) {
@@ -1011,7 +1013,7 @@
}
// Get the debug info (create it if it does not exist).
- FrameSummary summary = GetFirstFrameSummary(frame);
+ FrameSummary summary = FrameSummary::GetFirst(frame);
Handle<JSFunction> function(summary.function());
Handle<SharedFunctionInfo> shared(function->shared());
if (!EnsureDebugInfo(shared, function)) {
@@ -1022,7 +1024,7 @@
Handle<DebugInfo> debug_info(shared->GetDebugInfo());
// Refresh frame summary if the code has been recompiled for debugging.
if (AbstractCode::cast(shared->code()) != *summary.abstract_code()) {
- summary = GetFirstFrameSummary(frame);
+ summary = FrameSummary::GetFirst(frame);
}
int call_offset =
@@ -1604,7 +1606,7 @@
if (!shared->HasDebugInfo()) return false;
DCHECK(!frame->is_optimized());
- FrameSummary summary = GetFirstFrameSummary(frame);
+ FrameSummary summary = FrameSummary::GetFirst(frame);
Handle<DebugInfo> debug_info(shared->GetDebugInfo());
BreakLocation location =
@@ -1656,21 +1658,6 @@
}
-void Debug::RecordEvalCaller(Handle<Script> script) {
- script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
- // For eval scripts add information on the function from which eval was
- // called.
- StackTraceFrameIterator it(script->GetIsolate());
- if (!it.done()) {
- script->set_eval_from_shared(it.frame()->function()->shared());
- Code* code = it.frame()->LookupCode();
- int offset = static_cast<int>(
- it.frame()->pc() - code->instruction_start());
- script->set_eval_from_instructions_offset(offset);
- }
-}
-
-
MaybeHandle<Object> Debug::MakeExecutionState() {
// Create the execution state object.
Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()) };
@@ -1911,7 +1898,7 @@
exec_state,
event_data,
event_listener_data_ };
- Handle<JSReceiver> global(isolate_->global_proxy());
+ Handle<JSReceiver> global = isolate_->global_proxy();
Execution::TryCall(isolate_, Handle<JSFunction>::cast(event_listener_),
global, arraysize(argv), argv);
}
@@ -2260,7 +2247,7 @@
JavaScriptFrameIterator iterator(isolate_);
if (iterator.done()) return;
JavaScriptFrame* frame = iterator.frame();
- FrameSummary summary = GetFirstFrameSummary(frame);
+ FrameSummary summary = FrameSummary::GetFirst(frame);
int source_position =
summary.abstract_code()->SourcePosition(summary.code_offset());
Handle<Object> script_obj(summary.function()->shared()->script(), isolate_);
@@ -2271,8 +2258,10 @@
Handle<Script> script = Handle<Script>::cast(script_obj);
Handle<String> source(String::cast(script->source()));
Script::InitLineEnds(script);
- int line = Script::GetLineNumber(script, source_position);
- int column = Script::GetColumnNumber(script, source_position);
+ int line =
+ Script::GetLineNumber(script, source_position) - script->line_offset();
+ int column = Script::GetColumnNumber(script, source_position) -
+ (line == 0 ? script->column_offset() : 0);
Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
int line_start =
line == 0 ? 0 : Smi::cast(line_ends->get(line - 1))->value() + 1;
diff --git a/src/debug/debug.h b/src/debug/debug.h
index 501de63..2cdc151 100644
--- a/src/debug/debug.h
+++ b/src/debug/debug.h
@@ -498,9 +498,6 @@
static int ArchiveSpacePerThread();
void FreeThreadResources() { }
- // Record function from which eval was called.
- static void RecordEvalCaller(Handle<Script> script);
-
bool CheckExecutionState(int id) {
return is_active() && !debug_context().is_null() && break_id() != 0 &&
break_id() == id;
diff --git a/src/debug/debug.js b/src/debug/debug.js
index 7f06ca1..38934b0 100644
--- a/src/debug/debug.js
+++ b/src/debug/debug.js
@@ -894,10 +894,6 @@
return %GetFrameCount(this.break_id);
};
-ExecutionState.prototype.threadCount = function() {
- return %GetThreadCount(this.break_id);
-};
-
ExecutionState.prototype.frame = function(opt_index) {
// If no index supplied return the selected frame.
if (opt_index == null) opt_index = this.selected_frame;
@@ -2173,28 +2169,6 @@
};
-DebugCommandProcessor.prototype.threadsRequest_ = function(request, response) {
- // Get the number of threads.
- var total_threads = this.exec_state_.threadCount();
-
- // Get information for all threads.
- var threads = [];
- for (var i = 0; i < total_threads; i++) {
- var details = %GetThreadDetails(this.exec_state_.break_id, i);
- var thread_info = { current: details[0],
- id: details[1]
- };
- threads.push(thread_info);
- }
-
- // Create the response body.
- response.body = {
- totalThreads: total_threads,
- threads: threads
- };
-};
-
-
DebugCommandProcessor.prototype.suspendRequest_ = function(request, response) {
response.running = false;
};
@@ -2360,7 +2334,6 @@
"references": proto.referencesRequest_,
"source": proto.sourceRequest_,
"scripts": proto.scriptsRequest_,
- "threads": proto.threadsRequest_,
"suspend": proto.suspendRequest_,
"version": proto.versionRequest_,
"changelive": proto.changeLiveRequest_,
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
diff --git a/src/debug/liveedit.h b/src/debug/liveedit.h
index 67be70e..af74043 100644
--- a/src/debug/liveedit.h
+++ b/src/debug/liveedit.h
@@ -32,26 +32,39 @@
namespace internal {
// This class collects some specific information on structure of functions
-// in a particular script. It gets called from compiler all the time, but
-// actually records any data only when liveedit operation is in process;
-// in any other time this class is very cheap.
+// in a particular script.
//
// The primary interest of the Tracker is to record function scope structures
-// in order to analyze whether function code maybe safely patched (with new
+// in order to analyze whether function code may be safely patched (with new
// code successfully reading existing data from function scopes). The Tracker
// also collects compiled function codes.
-class LiveEditFunctionTracker {
+class LiveEditFunctionTracker : public AstTraversalVisitor {
public:
- explicit LiveEditFunctionTracker(Isolate* isolate, FunctionLiteral* fun);
- ~LiveEditFunctionTracker();
- void RecordFunctionInfo(Handle<SharedFunctionInfo> info,
- FunctionLiteral* lit, Zone* zone);
- void RecordRootFunctionInfo(Handle<Code> code);
+ // Traverses the entire AST, and records information about all
+ // FunctionLiterals for further use by LiveEdit code patching. The collected
+ // information is returned as a serialized array.
+ static Handle<JSArray> Collect(FunctionLiteral* node, Handle<Script> script,
+ Zone* zone, Isolate* isolate);
- static bool IsActive(Isolate* isolate);
+ virtual ~LiveEditFunctionTracker() {}
+ void VisitFunctionLiteral(FunctionLiteral* node) override;
private:
+ LiveEditFunctionTracker(Handle<Script> script, Zone* zone, Isolate* isolate);
+
+ void FunctionStarted(FunctionLiteral* fun);
+ void FunctionDone(Handle<SharedFunctionInfo> shared, Scope* scope);
+ Handle<Object> SerializeFunctionScope(Scope* scope);
+
+ Handle<Script> script_;
+ Zone* zone_;
Isolate* isolate_;
+
+ Handle<JSArray> result_;
+ int len_;
+ int current_parent_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(LiveEditFunctionTracker);
};
diff --git a/src/debug/mirrors.js b/src/debug/mirrors.js
index 881f303..d098c1c 100644
--- a/src/debug/mirrors.js
+++ b/src/debug/mirrors.js
@@ -16,8 +16,8 @@
var MapEntries;
var MapIteratorNext;
var MathMin = global.Math.min;
-var promiseStatusSymbol = utils.ImportNow("promise_status_symbol");
-var promiseValueSymbol = utils.ImportNow("promise_value_symbol");
+var promiseStateSymbol = utils.ImportNow("promise_state_symbol");
+var promiseResultSymbol = utils.ImportNow("promise_result_symbol");
var SetIteratorNext;
var SetValues;
var SymbolToString;
@@ -115,7 +115,7 @@
function ObjectIsPromise(value) {
return IS_RECEIVER(value) &&
- !IS_UNDEFINED(%DebugGetProperty(value, promiseStatusSymbol));
+ !IS_UNDEFINED(%DebugGetProperty(value, promiseStateSymbol));
}
@@ -256,13 +256,15 @@
// A copy of the scope types from runtime-debug.cc.
// NOTE: these constants should be backward-compatible, so
// add new ones to the end of this list.
-var ScopeType = { Global: 0,
- Local: 1,
- With: 2,
+var ScopeType = { Global: 0,
+ Local: 1,
+ With: 2,
Closure: 3,
- Catch: 4,
- Block: 5,
- Script: 6 };
+ Catch: 4,
+ Block: 5,
+ Script: 6,
+ Eval: 7,
+ };
/**
* Base class for all mirror objects.
@@ -1272,7 +1274,7 @@
function PromiseGetStatus_(value) {
- var status = %DebugGetProperty(value, promiseStatusSymbol);
+ var status = %DebugGetProperty(value, promiseStateSymbol);
if (status == 0) return "pending";
if (status == 1) return "resolved";
return "rejected";
@@ -1280,7 +1282,7 @@
function PromiseGetValue_(value) {
- return %DebugGetProperty(value, promiseValueSymbol);
+ return %DebugGetProperty(value, promiseResultSymbol);
}
@@ -1408,8 +1410,8 @@
function GeneratorGetStatus_(value) {
var continuation = %GeneratorGetContinuation(value);
- if (continuation < 0) return "running";
- if (continuation == 0) return "closed";
+ if (continuation < -1) return "running";
+ if (continuation == -1) return "closed";
return "suspended";
}
@@ -1495,6 +1497,12 @@
};
+PropertyMirror.prototype.toText = function() {
+ if (IS_SYMBOL(this.name_)) return %SymbolDescriptiveString(this.name_);
+ return this.name_;
+};
+
+
PropertyMirror.prototype.isIndexed = function() {
for (var i = 0; i < this.name_.length; i++) {
if (this.name_[i] < '0' || '9' < this.name_[i]) {
@@ -1529,11 +1537,6 @@
};
-PropertyMirror.prototype.insertionIndex = function() {
- return %DebugPropertyIndexFromDetails(this.details_);
-};
-
-
/**
* Returns whether this property has a getter defined through __defineGetter__.
* @return {booolean} True if this property has a getter
@@ -2027,10 +2030,10 @@
if (display_receiver) {
result += '.';
}
- result += property.name();
+ result += property.toText();
} else {
result += '[';
- result += property.name();
+ result += property.toText();
result += ']';
}
// Also known as - if the name in the function doesn't match the name