[runtime] Do not refer directly to the closure stored in the context
This is is a preparatory CL to detach the JSFunction from the Context. We mainly rewrite the DebugScopeInterator to no longer rely on the a JSFunction to be around. Additionally the empty_function needs to have a proper ScopeInfo now. Drive-by-fix: Improve ScopeInfo debug printing Bug: v8:7066 Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel Change-Id: I2f2fa0e78914a12e076384e0e1234c2322ad1ee8 Reviewed-on: https://chromium-review.googlesource.com/918721 Commit-Queue: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#52791}
This commit is contained in:
parent
e570e67383
commit
a3142476ba
@ -161,7 +161,7 @@ class Genesis BASE_EMBEDDED {
|
||||
// Creates some basic objects. Used for creating a context from scratch.
|
||||
void CreateRoots();
|
||||
// Creates the empty function. Used for creating a context from scratch.
|
||||
Handle<JSFunction> CreateEmptyFunction(Isolate* isolate);
|
||||
Handle<JSFunction> CreateEmptyFunction();
|
||||
// Returns the %ThrowTypeError% intrinsic function.
|
||||
// See ES#sec-%throwtypeerror% for details.
|
||||
Handle<JSFunction> GetThrowTypeErrorIntrinsic();
|
||||
@ -590,29 +590,33 @@ V8_NOINLINE void InstallSpeciesGetter(Handle<JSFunction> constructor) {
|
||||
|
||||
} // namespace
|
||||
|
||||
Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
Handle<JSFunction> Genesis::CreateEmptyFunction() {
|
||||
// Allocate the function map first and then patch the prototype later.
|
||||
Handle<Map> empty_function_map = factory->CreateSloppyFunctionMap(
|
||||
Handle<Map> empty_function_map = factory()->CreateSloppyFunctionMap(
|
||||
FUNCTION_WITHOUT_PROTOTYPE, MaybeHandle<JSFunction>());
|
||||
empty_function_map->set_is_prototype_map(true);
|
||||
DCHECK(!empty_function_map->is_dictionary_map());
|
||||
|
||||
// Allocate ScopeInfo for the empty function.
|
||||
Handle<ScopeInfo> scope_info = ScopeInfo::CreateForEmptyFunction(isolate());
|
||||
|
||||
// Allocate the empty function as the prototype for function according to
|
||||
// ES#sec-properties-of-the-function-prototype-object
|
||||
NewFunctionArgs args = NewFunctionArgs::ForBuiltin(
|
||||
factory->empty_string(), empty_function_map, Builtins::kEmptyFunction);
|
||||
Handle<JSFunction> empty_function = factory->NewFunction(args);
|
||||
factory()->empty_string(), empty_function_map, Builtins::kEmptyFunction);
|
||||
Handle<JSFunction> empty_function = factory()->NewFunction(args);
|
||||
native_context()->set_empty_function(*empty_function);
|
||||
|
||||
// --- E m p t y ---
|
||||
Handle<String> source = factory->NewStringFromStaticChars("() {}");
|
||||
Handle<Script> script = factory->NewScript(source);
|
||||
Handle<String> source = factory()->NewStringFromStaticChars("() {}");
|
||||
Handle<Script> script = factory()->NewScript(source);
|
||||
script->set_type(Script::TYPE_NATIVE);
|
||||
Handle<WeakFixedArray> infos = factory->NewWeakFixedArray(2);
|
||||
Handle<WeakFixedArray> infos = factory()->NewWeakFixedArray(2);
|
||||
script->set_shared_function_infos(*infos);
|
||||
// TODO(cbruni): fix position information here.
|
||||
empty_function->shared()->set_raw_start_position(0);
|
||||
empty_function->shared()->set_raw_end_position(source->length());
|
||||
empty_function->shared()->set_scope_info(*scope_info);
|
||||
empty_function->shared()->set_function_literal_id(1);
|
||||
empty_function->shared()->DontAdaptArguments();
|
||||
SharedFunctionInfo::SetScript(handle(empty_function->shared()), script);
|
||||
@ -5385,7 +5389,7 @@ Genesis::Genesis(
|
||||
DCHECK_EQ(0u, context_snapshot_index);
|
||||
// We get here if there was no context snapshot.
|
||||
CreateRoots();
|
||||
Handle<JSFunction> empty_function = CreateEmptyFunction(isolate);
|
||||
Handle<JSFunction> empty_function = CreateEmptyFunction();
|
||||
CreateSloppyModeFunctionMaps(empty_function);
|
||||
CreateStrictModeFunctionMaps(empty_function);
|
||||
CreateObjectFunction(empty_function);
|
||||
|
@ -764,7 +764,8 @@ TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
|
||||
|
||||
BIND(&throwtypeerror);
|
||||
{
|
||||
Node* name = CallRuntime(Runtime::kGetFunctionName, context, target);
|
||||
TNode<String> name =
|
||||
CAST(CallRuntime(Runtime::kGetFunctionName, context, target));
|
||||
ThrowTypeError(context, MessageTemplate::kConstructorNotFunction, name);
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +114,11 @@ JSReceiver* Context::extension_receiver() {
|
||||
: extension_object();
|
||||
}
|
||||
|
||||
ScopeInfo* Context::raw_scope_info() {
|
||||
DCHECK(!IsNativeContext());
|
||||
return closure()->shared()->scope_info();
|
||||
}
|
||||
|
||||
ScopeInfo* Context::scope_info() {
|
||||
DCHECK(!IsNativeContext());
|
||||
if (IsFunctionContext() || IsModuleContext() || IsEvalContext()) {
|
||||
|
@ -137,6 +137,7 @@ enum ContextLookupFlags {
|
||||
V(DATA_VIEW_FUN_INDEX, JSFunction, data_view_fun) \
|
||||
V(DATE_FUNCTION_INDEX, JSFunction, date_function) \
|
||||
V(DEBUG_CONTEXT_ID_INDEX, Object, debug_context_id) \
|
||||
V(EMPTY_FUNCTION_INDEX, JSFunction, empty_function) \
|
||||
V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \
|
||||
error_message_for_code_gen_from_strings) \
|
||||
V(ERRORS_THROWN_INDEX, Smi, errors_thrown) \
|
||||
@ -487,6 +488,7 @@ class Context: public FixedArray {
|
||||
inline void set_extension(HeapObject* object);
|
||||
JSObject* extension_object();
|
||||
JSReceiver* extension_receiver();
|
||||
ScopeInfo* raw_scope_info();
|
||||
ScopeInfo* scope_info();
|
||||
String* catch_name();
|
||||
|
||||
|
@ -440,6 +440,9 @@ class ScopeIterator {
|
||||
virtual ScopeType GetType() = 0;
|
||||
virtual v8::Local<v8::Object> GetObject() = 0;
|
||||
virtual v8::Local<v8::Function> GetFunction() = 0;
|
||||
virtual v8::Local<v8::Value> GetFunctionDebugName() = 0;
|
||||
virtual int GetScriptId() = 0;
|
||||
virtual bool HasLocationInfo() = 0;
|
||||
virtual debug::Location GetStartLocation() = 0;
|
||||
virtual debug::Location GetEndLocation() = 0;
|
||||
|
||||
@ -463,7 +466,7 @@ class StackTraceIterator {
|
||||
virtual int GetContextId() const = 0;
|
||||
virtual v8::MaybeLocal<v8::Value> GetReceiver() const = 0;
|
||||
virtual v8::Local<v8::Value> GetReturnValue() const = 0;
|
||||
virtual v8::Local<v8::String> GetFunctionName() const = 0;
|
||||
virtual v8::Local<v8::String> GetFunctionDebugName() const = 0;
|
||||
virtual v8::Local<v8::debug::Script> GetScript() const = 0;
|
||||
virtual debug::Location GetSourceLocation() const = 0;
|
||||
virtual v8::Local<v8::Function> GetFunction() const = 0;
|
||||
|
@ -113,28 +113,34 @@ v8::Local<v8::Object> DebugScopeIterator::GetObject() {
|
||||
|
||||
v8::Local<v8::Function> DebugScopeIterator::GetFunction() {
|
||||
DCHECK(!Done());
|
||||
Handle<JSFunction> closure = iterator_.GetClosure();
|
||||
Handle<JSFunction> closure = iterator_.GetFunction();
|
||||
if (closure.is_null()) return v8::Local<v8::Function>();
|
||||
return Utils::ToLocal(closure);
|
||||
}
|
||||
int DebugScopeIterator::GetScriptId() {
|
||||
DCHECK(!Done());
|
||||
return iterator_.GetScript()->id();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> DebugScopeIterator::GetFunctionDebugName() {
|
||||
DCHECK(!Done());
|
||||
Handle<Object> name = iterator_.GetFunctionDebugName();
|
||||
return Utils::ToLocal(name);
|
||||
}
|
||||
|
||||
bool DebugScopeIterator::HasLocationInfo() {
|
||||
return iterator_.HasPositionInfo();
|
||||
}
|
||||
|
||||
debug::Location DebugScopeIterator::GetStartLocation() {
|
||||
DCHECK(!Done());
|
||||
Handle<JSFunction> closure = iterator_.GetClosure();
|
||||
if (closure.is_null()) return debug::Location();
|
||||
Object* obj = closure->shared()->script();
|
||||
if (!obj->IsScript()) return debug::Location();
|
||||
return ToApiHandle<v8::debug::Script>(handle(Script::cast(obj)))
|
||||
return ToApiHandle<v8::debug::Script>(iterator_.GetScript())
|
||||
->GetSourceLocation(iterator_.start_position());
|
||||
}
|
||||
|
||||
debug::Location DebugScopeIterator::GetEndLocation() {
|
||||
DCHECK(!Done());
|
||||
Handle<JSFunction> closure = iterator_.GetClosure();
|
||||
if (closure.is_null()) return debug::Location();
|
||||
Object* obj = closure->shared()->script();
|
||||
if (!obj->IsScript()) return debug::Location();
|
||||
return ToApiHandle<v8::debug::Script>(handle(Script::cast(obj)))
|
||||
return ToApiHandle<v8::debug::Script>(iterator_.GetScript())
|
||||
->GetSourceLocation(iterator_.end_position());
|
||||
}
|
||||
|
||||
@ -190,11 +196,23 @@ v8::Local<v8::Object> DebugWasmScopeIterator::GetObject() {
|
||||
return v8::Local<v8::Object>();
|
||||
}
|
||||
|
||||
int DebugWasmScopeIterator::GetScriptId() {
|
||||
DCHECK(!Done());
|
||||
return -1;
|
||||
}
|
||||
|
||||
v8::Local<v8::Function> DebugWasmScopeIterator::GetFunction() {
|
||||
DCHECK(!Done());
|
||||
return v8::Local<v8::Function>();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> DebugWasmScopeIterator::GetFunctionDebugName() {
|
||||
DCHECK(!Done());
|
||||
return Utils::ToLocal(isolate_->factory()->empty_string());
|
||||
}
|
||||
|
||||
bool DebugWasmScopeIterator::HasLocationInfo() { return false; }
|
||||
|
||||
debug::Location DebugWasmScopeIterator::GetStartLocation() {
|
||||
DCHECK(!Done());
|
||||
return debug::Location();
|
||||
|
@ -24,6 +24,9 @@ class DebugScopeIterator final : public debug::ScopeIterator {
|
||||
ScopeType GetType() override;
|
||||
v8::Local<v8::Object> GetObject() override;
|
||||
v8::Local<v8::Function> GetFunction() override;
|
||||
v8::Local<v8::Value> GetFunctionDebugName() override;
|
||||
int GetScriptId() override;
|
||||
bool HasLocationInfo() override;
|
||||
debug::Location GetStartLocation() override;
|
||||
debug::Location GetEndLocation() override;
|
||||
|
||||
@ -46,12 +49,14 @@ class DebugWasmScopeIterator final : public debug::ScopeIterator {
|
||||
ScopeType GetType() override;
|
||||
v8::Local<v8::Object> GetObject() override;
|
||||
v8::Local<v8::Function> GetFunction() override;
|
||||
v8::Local<v8::Value> GetFunctionDebugName() override;
|
||||
int GetScriptId() override;
|
||||
bool HasLocationInfo() override;
|
||||
debug::Location GetStartLocation() override;
|
||||
debug::Location GetEndLocation() override;
|
||||
|
||||
bool SetVariableValue(v8::Local<v8::String> name,
|
||||
v8::Local<v8::Value> value) override;
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
StandardFrame* frame_;
|
||||
|
@ -23,11 +23,14 @@ ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
|
||||
ScopeIterator::Option option)
|
||||
: isolate_(isolate),
|
||||
frame_inspector_(frame_inspector),
|
||||
function_(frame_inspector_->GetFunction()),
|
||||
script_(frame_inspector_->GetScript()),
|
||||
seen_script_scope_(false) {
|
||||
if (!frame_inspector->GetContext()->IsContext()) {
|
||||
// Optimized frame, context or function cannot be materialized. Give up.
|
||||
return;
|
||||
}
|
||||
context_ = Handle<Context>::cast(frame_inspector->GetContext());
|
||||
|
||||
// We should not instantiate a ScopeIterator for wasm frames.
|
||||
DCHECK(frame_inspector->GetScript()->type() != Script::TYPE_WASM);
|
||||
@ -35,17 +38,47 @@ ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
|
||||
TryParseAndRetrieveScopes(option);
|
||||
}
|
||||
|
||||
void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
|
||||
context_ = GetContext();
|
||||
Handle<Object> ScopeIterator::GetFunctionDebugName() const {
|
||||
if (HasNestedScopeChain()) return JSFunction::GetDebugName(function_);
|
||||
if (!context_->IsNativeContext()) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
Handle<String> debug_name(context_->raw_scope_info()->FunctionDebugName());
|
||||
if (debug_name->length() > 0) return debug_name;
|
||||
}
|
||||
return isolate_->factory()->undefined_value();
|
||||
}
|
||||
|
||||
ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
|
||||
: isolate_(isolate),
|
||||
context_(function->context()),
|
||||
script_(Script::cast(function->shared()->script())),
|
||||
seen_script_scope_(false) {
|
||||
if (!function->shared()->IsSubjectToDebugging()) context_ = Handle<Context>();
|
||||
UnwrapEvaluationContext();
|
||||
}
|
||||
|
||||
ScopeIterator::ScopeIterator(Isolate* isolate,
|
||||
Handle<JSGeneratorObject> generator)
|
||||
: isolate_(isolate),
|
||||
generator_(generator),
|
||||
function_(generator->function()),
|
||||
context_(generator->context()),
|
||||
script_(Script::cast(function_->shared()->script())),
|
||||
seen_script_scope_(false) {
|
||||
if (!function_->shared()->IsSubjectToDebugging()) {
|
||||
context_ = Handle<Context>();
|
||||
return;
|
||||
}
|
||||
TryParseAndRetrieveScopes(DEFAULT);
|
||||
}
|
||||
|
||||
void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
|
||||
// Catch the case when the debugger stops in an internal function.
|
||||
Handle<JSFunction> function = GetFunction();
|
||||
Handle<SharedFunctionInfo> shared_info(function->shared());
|
||||
Handle<SharedFunctionInfo> shared_info(function_->shared());
|
||||
Handle<ScopeInfo> scope_info(shared_info->scope_info());
|
||||
if (shared_info->script()->IsUndefined(isolate_)) {
|
||||
while (context_->closure() == *function) {
|
||||
context_ = Handle<Context>(context_->previous(), isolate_);
|
||||
}
|
||||
context_ = handle(function_->context());
|
||||
function_ = Handle<JSFunction>();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -77,9 +110,7 @@ void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
|
||||
if (scope_info->HasContext()) {
|
||||
context_ = Handle<Context>(context_->declaration_context(), isolate_);
|
||||
} else {
|
||||
while (context_->closure() == *function) {
|
||||
context_ = Handle<Context>(context_->previous(), isolate_);
|
||||
}
|
||||
context_ = handle(function_->context());
|
||||
}
|
||||
if (scope_info->scope_type() == FUNCTION_SCOPE) {
|
||||
nested_scope_chain_.emplace_back(scope_info, shared_info->StartPosition(),
|
||||
@ -97,8 +128,8 @@ void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
|
||||
info.reset(new ParseInfo(script));
|
||||
if (scope_info->scope_type() == EVAL_SCOPE) {
|
||||
info->set_eval();
|
||||
if (!function->context()->IsNativeContext()) {
|
||||
info->set_outer_scope_info(handle(function->context()->scope_info()));
|
||||
if (!function_->context()->IsNativeContext()) {
|
||||
info->set_outer_scope_info(handle(function_->context()->scope_info()));
|
||||
}
|
||||
// Language mode may be inherited from the eval caller.
|
||||
// Retrieve it from shared function info.
|
||||
@ -141,27 +172,6 @@ void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
|
||||
UnwrapEvaluationContext();
|
||||
}
|
||||
|
||||
ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
|
||||
: isolate_(isolate),
|
||||
context_(function->context()),
|
||||
seen_script_scope_(false) {
|
||||
if (!function->shared()->IsSubjectToDebugging()) context_ = Handle<Context>();
|
||||
UnwrapEvaluationContext();
|
||||
}
|
||||
|
||||
ScopeIterator::ScopeIterator(Isolate* isolate,
|
||||
Handle<JSGeneratorObject> generator)
|
||||
: isolate_(isolate),
|
||||
generator_(generator),
|
||||
context_(generator->context()),
|
||||
seen_script_scope_(false) {
|
||||
if (!generator->function()->shared()->IsSubjectToDebugging()) {
|
||||
context_ = Handle<Context>();
|
||||
return;
|
||||
}
|
||||
TryParseAndRetrieveScopes(DEFAULT);
|
||||
}
|
||||
|
||||
void ScopeIterator::UnwrapEvaluationContext() {
|
||||
while (true) {
|
||||
if (context_.is_null()) return;
|
||||
@ -188,46 +198,37 @@ ScopeIterator::MaterializeScopeDetails() {
|
||||
details->set(kScopeDetailsObjectIndex, *scope_object);
|
||||
if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) {
|
||||
return isolate_->factory()->NewJSArrayWithElements(details);
|
||||
}
|
||||
|
||||
Handle<JSFunction> js_function = GetClosure();
|
||||
if (!js_function.is_null()) {
|
||||
Handle<String> closure_name = JSFunction::GetDebugName(js_function);
|
||||
if (!closure_name.is_null() && closure_name->length() != 0) {
|
||||
} else if (HasContext()) {
|
||||
Handle<Object> closure_name = GetFunctionDebugName();
|
||||
details->set(kScopeDetailsNameIndex, *closure_name);
|
||||
}
|
||||
details->set(kScopeDetailsStartPositionIndex,
|
||||
Smi::FromInt(start_position()));
|
||||
details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position()));
|
||||
details->set(kScopeDetailsFunctionIndex, *js_function);
|
||||
if (HasNestedScopeChain()) {
|
||||
details->set(kScopeDetailsFunctionIndex, *function_);
|
||||
}
|
||||
}
|
||||
return isolate_->factory()->NewJSArrayWithElements(details);
|
||||
}
|
||||
|
||||
Handle<JSFunction> ScopeIterator::GetClosure() {
|
||||
if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript)
|
||||
return Handle<JSFunction>::null();
|
||||
if (HasNestedScopeChain()) return GetFunction();
|
||||
return HasContext() ? handle(CurrentContext()->closure())
|
||||
: Handle<JSFunction>::null();
|
||||
bool ScopeIterator::HasPositionInfo() {
|
||||
return HasNestedScopeChain() || !context_->IsNativeContext();
|
||||
}
|
||||
|
||||
int ScopeIterator::start_position() {
|
||||
if (HasNestedScopeChain()) {
|
||||
return LastNestedScopeChain().start_position;
|
||||
}
|
||||
if (!HasContext()) return 0;
|
||||
Handle<JSFunction> js_function = handle(CurrentContext()->closure());
|
||||
return js_function.is_null() ? 0 : js_function->shared()->StartPosition();
|
||||
if (context_->IsNativeContext()) return 0;
|
||||
return context_->raw_scope_info()->StartPosition();
|
||||
}
|
||||
|
||||
int ScopeIterator::end_position() {
|
||||
if (HasNestedScopeChain()) {
|
||||
return LastNestedScopeChain().end_position;
|
||||
}
|
||||
if (!HasContext()) return 0;
|
||||
Handle<JSFunction> js_function = handle(CurrentContext()->closure());
|
||||
return js_function.is_null() ? 0 : js_function->shared()->EndPosition();
|
||||
if (context_->IsNativeContext()) return 0;
|
||||
return context_->raw_scope_info()->EndPosition();
|
||||
}
|
||||
|
||||
void ScopeIterator::Next() {
|
||||
@ -261,6 +262,7 @@ void ScopeIterator::Next() {
|
||||
// Repeat to skip hidden scopes.
|
||||
} while (LastNestedScopeChain().is_hidden());
|
||||
}
|
||||
if (!HasNestedScopeChain()) function_ = Handle<JSFunction>();
|
||||
UnwrapEvaluationContext();
|
||||
}
|
||||
|
||||
@ -427,7 +429,7 @@ void ScopeIterator::DebugPrint() {
|
||||
|
||||
case ScopeIterator::ScopeTypeLocal: {
|
||||
os << "Local:\n";
|
||||
GetFunction()->shared()->scope_info()->Print();
|
||||
function_->shared()->scope_info()->Print();
|
||||
if (!CurrentContext().is_null()) {
|
||||
CurrentContext()->Print(os);
|
||||
if (CurrentContext()->has_extension()) {
|
||||
@ -478,24 +480,6 @@ void ScopeIterator::DebugPrint() {
|
||||
}
|
||||
#endif
|
||||
|
||||
inline Handle<Context> ScopeIterator::GetContext() {
|
||||
if (frame_inspector_) {
|
||||
return Handle<Context>::cast(frame_inspector_->GetContext());
|
||||
} else {
|
||||
DCHECK(!generator_.is_null());
|
||||
return handle(generator_->context());
|
||||
}
|
||||
}
|
||||
|
||||
Handle<JSFunction> ScopeIterator::GetFunction() {
|
||||
if (frame_inspector_) {
|
||||
return frame_inspector_->GetFunction();
|
||||
} else {
|
||||
DCHECK(!generator_.is_null());
|
||||
return handle(generator_->function());
|
||||
}
|
||||
}
|
||||
|
||||
int ScopeIterator::GetSourcePosition() {
|
||||
if (frame_inspector_) {
|
||||
return frame_inspector_->GetSourcePosition();
|
||||
@ -561,26 +545,24 @@ void ScopeIterator::MaterializeStackLocals(Handle<JSObject> local_scope,
|
||||
}
|
||||
|
||||
MaybeHandle<JSObject> ScopeIterator::MaterializeLocalScope() {
|
||||
Handle<JSFunction> function(GetFunction());
|
||||
Handle<SharedFunctionInfo> shared(function->shared());
|
||||
DCHECK(HasNestedScopeChain());
|
||||
Handle<SharedFunctionInfo> shared(function_->shared());
|
||||
Handle<ScopeInfo> scope_info(shared->scope_info());
|
||||
|
||||
Handle<JSObject> local_scope =
|
||||
isolate_->factory()->NewJSObjectWithNullProto();
|
||||
MaterializeStackLocals(local_scope, scope_info);
|
||||
|
||||
Handle<Context> frame_context = GetContext();
|
||||
|
||||
if (!scope_info->HasContext()) return local_scope;
|
||||
|
||||
// Fill all context locals.
|
||||
Handle<Context> function_context(frame_context->closure_context());
|
||||
Handle<Context> function_context(context_->closure_context());
|
||||
DCHECK_EQ(context_->scope_info(), *scope_info);
|
||||
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->IsNativeContext()) {
|
||||
if (!function_context->IsNativeContext()) {
|
||||
CopyContextExtensionToScopeObject(function_context, local_scope,
|
||||
KeyCollectionMode::kIncludePrototypes);
|
||||
}
|
||||
@ -595,8 +577,7 @@ Handle<JSObject> ScopeIterator::MaterializeClosure() {
|
||||
Handle<Context> context = CurrentContext();
|
||||
DCHECK(context->IsFunctionContext() || context->IsEvalContext());
|
||||
|
||||
Handle<SharedFunctionInfo> shared(context->closure()->shared());
|
||||
Handle<ScopeInfo> scope_info(shared->scope_info());
|
||||
Handle<ScopeInfo> scope_info(context_->scope_info());
|
||||
|
||||
// Allocate and initialize a JSObject with all the content of this function
|
||||
// closure.
|
||||
@ -610,7 +591,6 @@ Handle<JSObject> ScopeIterator::MaterializeClosure() {
|
||||
// be variables introduced by eval.
|
||||
CopyContextExtensionToScopeObject(context, closure_scope,
|
||||
KeyCollectionMode::kOwnOnly);
|
||||
|
||||
return closure_scope;
|
||||
}
|
||||
|
||||
@ -765,7 +745,14 @@ bool ScopeIterator::SetContextVariableValue(Handle<ScopeInfo> scope_info,
|
||||
|
||||
bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
|
||||
Handle<Object> new_value) {
|
||||
Handle<ScopeInfo> scope_info(GetFunction()->shared()->scope_info());
|
||||
Handle<ScopeInfo> scope_info;
|
||||
if (HasNestedScopeChain()) {
|
||||
scope_info = handle(function_->shared()->scope_info());
|
||||
DCHECK_IMPLIES(scope_info->HasContext(),
|
||||
context_->scope_info() == *scope_info);
|
||||
} else {
|
||||
scope_info = handle(context_->scope_info());
|
||||
}
|
||||
|
||||
// Parameter might be shadowed in context. Don't stop here.
|
||||
bool result = SetParameterValue(scope_info, variable_name, new_value);
|
||||
@ -776,8 +763,7 @@ bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
|
||||
}
|
||||
|
||||
if (scope_info->HasContext() &&
|
||||
SetContextVariableValue(scope_info, CurrentContext(), variable_name,
|
||||
new_value)) {
|
||||
SetContextVariableValue(scope_info, context_, variable_name, new_value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -981,7 +967,7 @@ void ScopeIterator::GetNestedScopeChain(Isolate* isolate, Scope* scope,
|
||||
}
|
||||
}
|
||||
|
||||
bool ScopeIterator::HasNestedScopeChain() {
|
||||
bool ScopeIterator::HasNestedScopeChain() const {
|
||||
return !nested_scope_chain_.empty();
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,14 @@ class ScopeIterator {
|
||||
Handle<StringSet> GetNonLocals();
|
||||
|
||||
// Return function which represents closure for current scope.
|
||||
Handle<JSFunction> GetClosure();
|
||||
Handle<JSFunction> GetFunction() { return function_; }
|
||||
// Similar to JSFunction::GetName return the function's name or it's inferred
|
||||
// name.
|
||||
Handle<Object> GetFunctionDebugName() const;
|
||||
|
||||
Handle<Script> GetScript() const { return script_; }
|
||||
|
||||
bool HasPositionInfo();
|
||||
int start_position();
|
||||
int end_position();
|
||||
|
||||
@ -102,7 +109,10 @@ class ScopeIterator {
|
||||
Isolate* isolate_;
|
||||
FrameInspector* const frame_inspector_ = nullptr;
|
||||
Handle<JSGeneratorObject> generator_;
|
||||
Handle<JSFunction> function_;
|
||||
Handle<ScopeInfo> function_scope_info_;
|
||||
Handle<Context> context_;
|
||||
Handle<Script> script_;
|
||||
std::vector<ExtendedScopeInfo> nested_scope_chain_;
|
||||
Handle<StringSet> non_locals_;
|
||||
bool seen_script_scope_;
|
||||
@ -112,7 +122,6 @@ class ScopeIterator {
|
||||
}
|
||||
|
||||
Handle<Context> GetContext();
|
||||
Handle<JSFunction> GetFunction();
|
||||
int GetSourcePosition();
|
||||
|
||||
void MaterializeStackLocals(Handle<JSObject> local_scope,
|
||||
@ -176,7 +185,7 @@ class ScopeIterator {
|
||||
void GetNestedScopeChain(Isolate* isolate, Scope* scope,
|
||||
int statement_position);
|
||||
|
||||
bool HasNestedScopeChain();
|
||||
bool HasNestedScopeChain() const;
|
||||
ExtendedScopeInfo& LastNestedScopeChain();
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
|
||||
|
@ -125,7 +125,7 @@ v8::Local<v8::Value> DebugStackTraceIterator::GetReturnValue() const {
|
||||
return Utils::ToLocal(isolate_->debug()->return_value_handle());
|
||||
}
|
||||
|
||||
v8::Local<v8::String> DebugStackTraceIterator::GetFunctionName() const {
|
||||
v8::Local<v8::String> DebugStackTraceIterator::GetFunctionDebugName() const {
|
||||
DCHECK(!Done());
|
||||
return Utils::ToLocal(frame_inspector_->GetFunctionName());
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class DebugStackTraceIterator final : public debug::StackTraceIterator {
|
||||
int GetContextId() const override;
|
||||
v8::MaybeLocal<v8::Value> GetReceiver() const override;
|
||||
v8::Local<v8::Value> GetReturnValue() const override;
|
||||
v8::Local<v8::String> GetFunctionName() const override;
|
||||
v8::Local<v8::String> GetFunctionDebugName() const override;
|
||||
v8::Local<v8::debug::Script> GetScript() const override;
|
||||
debug::Location GetSourceLocation() const override;
|
||||
v8::Local<v8::Function> GetFunction() const override;
|
||||
|
@ -255,26 +255,33 @@ Response buildScopes(v8::debug::ScopeIterator* iterator,
|
||||
std::unique_ptr<Array<Scope>>* scopes) {
|
||||
*scopes = Array<Scope>::create();
|
||||
if (!injectedScript) return Response::OK();
|
||||
if (iterator->Done()) return Response::OK();
|
||||
|
||||
String16 scriptId = String16::fromInteger(iterator->GetScriptId());
|
||||
|
||||
for (; !iterator->Done(); iterator->Advance()) {
|
||||
std::unique_ptr<RemoteObject> object;
|
||||
Response result = injectedScript->wrapObject(
|
||||
iterator->GetObject(), kBacktraceObjectGroup, false, false, &object);
|
||||
if (!result.isSuccess()) return result;
|
||||
|
||||
auto scope = Scope::create()
|
||||
.setType(scopeType(iterator->GetType()))
|
||||
.setObject(std::move(object))
|
||||
.build();
|
||||
v8::Local<v8::Function> closure = iterator->GetFunction();
|
||||
if (!closure.IsEmpty()) {
|
||||
String16 name = toProtocolStringWithTypeCheck(closure->GetDebugName());
|
||||
|
||||
String16 name =
|
||||
toProtocolStringWithTypeCheck(iterator->GetFunctionDebugName());
|
||||
if (!name.isEmpty()) scope->setName(name);
|
||||
String16 scriptId = String16::fromInteger(closure->ScriptId());
|
||||
|
||||
if (iterator->HasLocationInfo()) {
|
||||
v8::debug::Location start = iterator->GetStartLocation();
|
||||
scope->setStartLocation(protocol::Debugger::Location::create()
|
||||
.setScriptId(scriptId)
|
||||
.setLineNumber(start.GetLineNumber())
|
||||
.setColumnNumber(start.GetColumnNumber())
|
||||
.build());
|
||||
|
||||
v8::debug::Location end = iterator->GetEndLocation();
|
||||
scope->setEndLocation(protocol::Debugger::Location::create()
|
||||
.setScriptId(scriptId)
|
||||
@ -1335,7 +1342,7 @@ Response V8DebuggerAgentImpl::currentCallFrames(
|
||||
auto frame =
|
||||
CallFrame::create()
|
||||
.setCallFrameId(callFrameId)
|
||||
.setFunctionName(toProtocolString(iterator->GetFunctionName()))
|
||||
.setFunctionName(toProtocolString(iterator->GetFunctionDebugName()))
|
||||
.setLocation(std::move(location))
|
||||
.setUrl(url)
|
||||
.setScopeChain(std::move(scopes))
|
||||
|
@ -653,6 +653,11 @@ v8::MaybeLocal<v8::Value> V8Debugger::getTargetScopes(
|
||||
v8::Local<v8::Function> closure = iterator->GetFunction();
|
||||
if (!closure.IsEmpty()) {
|
||||
name = toProtocolStringWithTypeCheck(closure->GetDebugName());
|
||||
} else {
|
||||
v8::Local<v8::Value> maybe_name = iterator->GetFunctionDebugName();
|
||||
if (!maybe_name->IsUndefined()) {
|
||||
name = toProtocolStringWithTypeCheck(maybe_name);
|
||||
}
|
||||
}
|
||||
v8::Local<v8::Object> object = iterator->GetObject();
|
||||
createDataProperty(context, scope,
|
||||
|
@ -1798,13 +1798,28 @@ void ScopeInfo::ScopeInfoPrint(std::ostream& os) { // NOLINT
|
||||
os << "\n - length = 0\n";
|
||||
return;
|
||||
}
|
||||
int flags = Flags();
|
||||
|
||||
os << "\n - parameters: " << ParameterCount();
|
||||
os << "\n - stack locals: " << StackLocalCount();
|
||||
os << "\n - context locals : " << ContextLocalCount();
|
||||
|
||||
os << "\n - scope type: " << scope_type();
|
||||
if (CallsSloppyEval()) os << "\n - sloppy eval";
|
||||
os << "\n - language mode: " << language_mode();
|
||||
os << "\n - local count: " << LocalCount();
|
||||
os << "\n - stack slot count: " << StackSlotCount();
|
||||
if (HasReceiver()) os << "\n - has receiver";
|
||||
if (is_declaration_scope()) os << "\n - declaration scope";
|
||||
if (HasReceiver()) {
|
||||
os << "\n - receiver: " << ReceiverVariableField::decode(flags);
|
||||
}
|
||||
if (HasNewTarget()) os << "\n - needs new target";
|
||||
if (HasFunctionName()) {
|
||||
os << "\n - function name(" << FunctionVariableField::decode(flags)
|
||||
<< "): ";
|
||||
FunctionName()->ShortPrint(os);
|
||||
}
|
||||
if (IsAsmModule()) os << "\n - asm module";
|
||||
if (HasSimpleParameters()) os << "\n - simple parameters";
|
||||
os << "\n - function kind: " << function_kind();
|
||||
if (HasOuterScopeInfo()) {
|
||||
os << "\n - outer scope info: " << Brief(OuterScopeInfo());
|
||||
}
|
||||
|
@ -13692,8 +13692,10 @@ void SharedFunctionInfo::set_debugger_hints(int value) {
|
||||
}
|
||||
|
||||
String* SharedFunctionInfo::DebugName() {
|
||||
if (Name()->length() == 0) return inferred_name();
|
||||
return Name();
|
||||
DisallowHeapAllocation no_gc;
|
||||
String* function_name = Name();
|
||||
if (function_name->length() > 0) return function_name;
|
||||
return inferred_name();
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -57,6 +57,7 @@ bool ScopeInfo::Equals(ScopeInfo* other) const {
|
||||
}
|
||||
#endif
|
||||
|
||||
// static
|
||||
Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
|
||||
MaybeHandle<ScopeInfo> outer_scope) {
|
||||
// Collect variables.
|
||||
@ -321,6 +322,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
|
||||
return scope_info;
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<ScopeInfo> ScopeInfo::CreateForWithScope(
|
||||
Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope) {
|
||||
const bool has_outer_scope_info = !outer_scope.is_null();
|
||||
@ -365,33 +367,49 @@ Handle<ScopeInfo> ScopeInfo::CreateForWithScope(
|
||||
return scope_info;
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
|
||||
DCHECK(isolate->bootstrapper()->IsActive());
|
||||
return CreateForBootstrapping(isolate, SCRIPT_SCOPE);
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<ScopeInfo> ScopeInfo::CreateForEmptyFunction(Isolate* isolate) {
|
||||
return CreateForBootstrapping(isolate, FUNCTION_SCOPE);
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<ScopeInfo> ScopeInfo::CreateForBootstrapping(Isolate* isolate,
|
||||
ScopeType type) {
|
||||
DCHECK(isolate->bootstrapper()->IsActive());
|
||||
DCHECK(type == SCRIPT_SCOPE || type == FUNCTION_SCOPE);
|
||||
|
||||
const int stack_local_count = 0;
|
||||
const int context_local_count = 1;
|
||||
const VariableAllocationInfo receiver_info = CONTEXT;
|
||||
const VariableAllocationInfo function_name_info = NONE;
|
||||
const bool has_receiver = true;
|
||||
const bool has_position_info = true;
|
||||
const int parameter_count = 0;
|
||||
const int stack_local_count = 0;
|
||||
const bool is_empty_function = type == FUNCTION_SCOPE;
|
||||
const int context_local_count = is_empty_function ? 0 : 1;
|
||||
const bool has_receiver = !is_empty_function;
|
||||
const bool has_inferred_function_name = is_empty_function;
|
||||
const bool has_position_info = true;
|
||||
const int length = kVariablePartIndex + parameter_count +
|
||||
(1 + stack_local_count) + 2 * context_local_count +
|
||||
(has_receiver ? 1 : 0) +
|
||||
(is_empty_function ? kFunctionNameEntries : 0) +
|
||||
(has_inferred_function_name ? 1 : 0) +
|
||||
(has_position_info ? kPositionInfoEntries : 0);
|
||||
|
||||
Factory* factory = isolate->factory();
|
||||
Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
|
||||
|
||||
// Encode the flags.
|
||||
int flags = ScopeTypeField::encode(SCRIPT_SCOPE) |
|
||||
CallsSloppyEvalField::encode(false) |
|
||||
int flags =
|
||||
ScopeTypeField::encode(type) | CallsSloppyEvalField::encode(false) |
|
||||
LanguageModeField::encode(LanguageMode::kSloppy) |
|
||||
DeclarationScopeField::encode(true) |
|
||||
ReceiverVariableField::encode(receiver_info) |
|
||||
FunctionVariableField::encode(function_name_info) |
|
||||
AsmModuleField::encode(false) |
|
||||
HasSimpleParametersField::encode(true) |
|
||||
ReceiverVariableField::encode(is_empty_function ? UNUSED : CONTEXT) |
|
||||
HasNewTargetField::encode(false) |
|
||||
FunctionVariableField::encode(is_empty_function ? UNUSED : NONE) |
|
||||
HasInferredFunctionNameField::encode(has_inferred_function_name) |
|
||||
AsmModuleField::encode(false) | HasSimpleParametersField::encode(true) |
|
||||
FunctionKindField::encode(FunctionKind::kNormalFunction) |
|
||||
HasOuterScopeInfoField::encode(false) |
|
||||
IsDebugEvaluateScopeField::encode(false);
|
||||
@ -408,28 +426,45 @@ Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
|
||||
|
||||
// Here we add info for context-allocated "this".
|
||||
DCHECK_EQ(index, scope_info->ContextLocalNamesIndex());
|
||||
if (context_local_count) {
|
||||
scope_info->set(index++, isolate->heap()->this_string());
|
||||
}
|
||||
DCHECK_EQ(index, scope_info->ContextLocalInfosIndex());
|
||||
if (context_local_count) {
|
||||
const uint32_t value = VariableModeField::encode(CONST) |
|
||||
InitFlagField::encode(kCreatedInitialized) |
|
||||
MaybeAssignedFlagField::encode(kNotAssigned);
|
||||
scope_info->set(index++, Smi::FromInt(value));
|
||||
}
|
||||
|
||||
// And here we record that this scopeinfo binds a receiver.
|
||||
DCHECK_EQ(index, scope_info->ReceiverInfoIndex());
|
||||
const int receiver_index = Context::MIN_CONTEXT_SLOTS + 0;
|
||||
if (!is_empty_function) {
|
||||
scope_info->set(index++, Smi::FromInt(receiver_index));
|
||||
}
|
||||
|
||||
DCHECK_EQ(index, scope_info->FunctionNameInfoIndex());
|
||||
if (is_empty_function) {
|
||||
scope_info->set(index++, *isolate->factory()->empty_string());
|
||||
scope_info->set(index++, Smi::kZero);
|
||||
}
|
||||
DCHECK_EQ(index, scope_info->InferredFunctionNameIndex());
|
||||
if (has_inferred_function_name) {
|
||||
scope_info->set(index++, *isolate->factory()->empty_string());
|
||||
}
|
||||
DCHECK_EQ(index, scope_info->PositionInfoIndex());
|
||||
// Store dummy position to be in sync with the {scope_type}.
|
||||
scope_info->set(index++, Smi::kZero);
|
||||
scope_info->set(index++, Smi::kZero);
|
||||
DCHECK_EQ(index, scope_info->OuterScopeInfoIndex());
|
||||
DCHECK_EQ(index, scope_info->length());
|
||||
DCHECK_EQ(scope_info->ParameterCount(), 0);
|
||||
DCHECK_EQ(scope_info->ParameterCount(), parameter_count);
|
||||
if (type == FUNCTION_SCOPE) {
|
||||
DCHECK_EQ(scope_info->ContextLength(), 0);
|
||||
} else {
|
||||
DCHECK_EQ(scope_info->ContextLength(), Context::MIN_CONTEXT_SLOTS + 1);
|
||||
}
|
||||
|
||||
return scope_info;
|
||||
}
|
||||
@ -576,6 +611,18 @@ Object* ScopeInfo::InferredFunctionName() const {
|
||||
return get(InferredFunctionNameIndex());
|
||||
}
|
||||
|
||||
String* ScopeInfo::FunctionDebugName() const {
|
||||
Object* name = FunctionName();
|
||||
if (name->IsString() && String::cast(name)->length() > 0) {
|
||||
return String::cast(name);
|
||||
}
|
||||
if (HasInferredFunctionName()) {
|
||||
name = InferredFunctionName();
|
||||
if (name->IsString()) return String::cast(name);
|
||||
}
|
||||
return GetHeap()->empty_string();
|
||||
}
|
||||
|
||||
int ScopeInfo::StartPosition() const {
|
||||
DCHECK(HasPositionInfo());
|
||||
return Smi::cast(get(PositionInfoIndex()))->value();
|
||||
@ -877,6 +924,22 @@ void ScopeInfo::ModuleVariable(int i, String** name, int* index,
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
ScopeInfo::VariableAllocationInfo var_info) {
|
||||
switch (var_info) {
|
||||
case ScopeInfo::VariableAllocationInfo::NONE:
|
||||
return os << "NONE";
|
||||
case ScopeInfo::VariableAllocationInfo::STACK:
|
||||
return os << "STACK";
|
||||
case ScopeInfo::VariableAllocationInfo::CONTEXT:
|
||||
return os << "CONTEXT";
|
||||
case ScopeInfo::VariableAllocationInfo::UNUSED:
|
||||
return os << "UNUSED";
|
||||
}
|
||||
UNREACHABLE();
|
||||
return os;
|
||||
}
|
||||
|
||||
Handle<ModuleInfoEntry> ModuleInfoEntry::New(Isolate* isolate,
|
||||
Handle<Object> export_name,
|
||||
Handle<Object> local_name,
|
||||
|
@ -103,6 +103,10 @@ class ScopeInfo : public FixedArray {
|
||||
// Return the function_name if present.
|
||||
Object* FunctionName() const;
|
||||
|
||||
// The function's name if it is non-empty, otherwise the inferred name or an
|
||||
// empty string.
|
||||
String* FunctionDebugName() const;
|
||||
|
||||
// Return the function's inferred name if present.
|
||||
// See SharedFunctionInfo::function_identifier.
|
||||
Object* InferredFunctionName() const;
|
||||
@ -203,6 +207,7 @@ class ScopeInfo : public FixedArray {
|
||||
MaybeHandle<ScopeInfo> outer_scope);
|
||||
static Handle<ScopeInfo> CreateForWithScope(
|
||||
Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope);
|
||||
static Handle<ScopeInfo> CreateForEmptyFunction(Isolate* isolate);
|
||||
static Handle<ScopeInfo> CreateGlobalThisBinding(Isolate* isolate);
|
||||
|
||||
// Serializes empty scope info.
|
||||
@ -295,6 +300,8 @@ class ScopeInfo : public FixedArray {
|
||||
int ModuleVariablesIndex() const;
|
||||
|
||||
static bool NeedsPositionInfo(ScopeType type);
|
||||
static Handle<ScopeInfo> CreateForBootstrapping(Isolate* isolate,
|
||||
ScopeType type);
|
||||
|
||||
int Lookup(Handle<String> name, int start, int end, VariableMode* mode,
|
||||
VariableLocation* location, InitializationFlag* init_flag,
|
||||
@ -354,8 +361,13 @@ class ScopeInfo : public FixedArray {
|
||||
class MaybeAssignedFlagField : public BitField<MaybeAssignedFlag, 4, 1> {};
|
||||
|
||||
friend class ScopeIterator;
|
||||
friend std::ostream& operator<<(std::ostream& os,
|
||||
ScopeInfo::VariableAllocationInfo var);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
ScopeInfo::VariableAllocationInfo var);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -722,6 +722,89 @@ closure_9();
|
||||
EndTest();
|
||||
|
||||
|
||||
// Closure with inferred name.
|
||||
BeginTest("Closure with Inferred Name 1");
|
||||
|
||||
function closure_1_inferred_name(a) {
|
||||
let foo = {};
|
||||
foo.bar = function() {
|
||||
debugger;
|
||||
return a;
|
||||
};
|
||||
return foo.bar;
|
||||
}
|
||||
|
||||
listener_delegate = function(exec_state) {
|
||||
CheckScopeChain([debug.ScopeType.Local,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], exec_state);
|
||||
CheckScopeContent({a:1}, 1, exec_state);
|
||||
CheckScopeChainNames(["foo.bar", "closure_1_inferred_name", undefined,
|
||||
undefined], exec_state);
|
||||
};
|
||||
closure_1_inferred_name(1)();
|
||||
EndTest();
|
||||
|
||||
// Closure with nested inferred name.
|
||||
BeginTest("Closure with Inferred Name 2");
|
||||
|
||||
function closure_2_inferred_name(a) {
|
||||
let foo = {};
|
||||
function FooBar(b) {
|
||||
foo.baz = function() {
|
||||
debugger;
|
||||
return a+b;
|
||||
}
|
||||
return foo.baz;
|
||||
};
|
||||
return FooBar;
|
||||
}
|
||||
|
||||
listener_delegate = function(exec_state) {
|
||||
CheckScopeChain([debug.ScopeType.Local,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], exec_state);
|
||||
CheckScopeContent({b:0x1235}, 1, exec_state);
|
||||
CheckScopeContent({a:0x1234}, 2, exec_state);
|
||||
CheckScopeChainNames(["FooBar.foo.baz", "FooBar", "closure_2_inferred_name",
|
||||
undefined, undefined], exec_state);
|
||||
};
|
||||
closure_2_inferred_name(0x1234)(0x1235)();
|
||||
EndTest();
|
||||
|
||||
|
||||
// Closure with nested inferred name.
|
||||
BeginTest("Closure with Inferred Name 3");
|
||||
|
||||
function closure_3_inferred_name(a) {
|
||||
let foo = {};
|
||||
foo.bar = function(b) {
|
||||
foo.baz = function() {
|
||||
debugger;
|
||||
return a+b;
|
||||
}
|
||||
return foo.baz;
|
||||
};
|
||||
return foo.bar;
|
||||
}
|
||||
|
||||
listener_delegate = function(exec_state) {
|
||||
CheckScopeChain([debug.ScopeType.Local,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], exec_state);
|
||||
CheckScopeContent({b:0x1235}, 1, exec_state);
|
||||
CheckScopeContent({a:0x1234}, 2, exec_state);
|
||||
CheckScopeChainNames(["foo.baz", "foo.bar", "closure_3_inferred_name",
|
||||
undefined, undefined], exec_state);
|
||||
};
|
||||
closure_3_inferred_name(0x1234)(0x1235)();
|
||||
EndTest();
|
||||
|
||||
BeginTest("Closure passed to optimized Array.prototype.forEach");
|
||||
function closure_10(a) {
|
||||
var x = a + 2;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
#include "src/compiler.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/objects.h"
|
||||
#include "test/unittests/test-utils.h"
|
||||
@ -149,5 +150,23 @@ TEST_F(ObjectWithIsolate, DictionaryGrowth) {
|
||||
CHECK_EQ(64, dict->Capacity());
|
||||
}
|
||||
|
||||
TEST_F(TestWithNativeContext, EmptyFunctionScopeInfo) {
|
||||
// Check that the empty_function has a properly set up ScopeInfo.
|
||||
Handle<JSFunction> function = RunJS<JSFunction>("(function(){})");
|
||||
|
||||
Handle<ScopeInfo> scope_info(function->shared()->scope_info());
|
||||
Handle<ScopeInfo> empty_function_scope_info(
|
||||
isolate()->empty_function()->shared()->scope_info());
|
||||
|
||||
EXPECT_EQ(scope_info->length(), empty_function_scope_info->length());
|
||||
EXPECT_EQ(scope_info->Flags(), empty_function_scope_info->Flags());
|
||||
EXPECT_EQ(scope_info->ParameterCount(),
|
||||
empty_function_scope_info->ParameterCount());
|
||||
EXPECT_EQ(scope_info->StackLocalCount(),
|
||||
empty_function_scope_info->StackLocalCount());
|
||||
EXPECT_EQ(scope_info->ContextLocalCount(),
|
||||
empty_function_scope_info->ContextLocalCount());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user