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