Introduce is_debuggable state bit on function objects

Simplify debugger logic. Any function can be marked as
non-debuggable when is is created. The debugger no longer
needs a heuristic which functions are debuggable.
Mostly used for synthetic, generated functions that
have no source code, e.g. async code, implicit getters and
setters, implicit constructors, forwarding constructors,
dispatcher functions.

Review URL: https://codereview.chromium.org//789643006

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@42570 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
hausner@google.com 2014-12-29 22:31:17 +00:00
parent 4dc4caa34d
commit ab3af6ec00
9 changed files with 53 additions and 30 deletions

View file

@ -1388,6 +1388,7 @@ void ClassFinalizer::ResolveAndFinalizeMemberTypes(const Class& cls) {
cls,
field.token_pos()));
getter.set_result_type(type);
getter.set_is_debuggable(false);
cls.AddFunction(getter);
field.set_value(Instance::Handle(I, Object::sentinel().raw()));
}
@ -2070,6 +2071,7 @@ void ClassFinalizer::CreateForwardingConstructors(
clone.SetNumOptionalParameters(func.NumOptionalParameters(),
func.HasOptionalPositionalParameters());
clone.set_result_type(dynamic_type);
clone.set_is_debuggable(false);
const intptr_t num_parameters = func.NumParameters();
// The cloned ctor shares the parameter names array with the

View file

@ -1164,6 +1164,7 @@ RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
func.SetNumOptionalParameters(0, true);
// Manually generated AST, do not recompile.
func.SetIsOptimizable(false);
func.set_is_debuggable(false);
// We compile the function here, even though InvokeFunction() below
// would compile func automatically. We are checking fewer invariants

View file

@ -111,6 +111,7 @@ void SourceBreakpoint::SetResolved(const Function& func, intptr_t token_pos) {
ASSERT(func.script() == script_);
ASSERT((func.token_pos() <= token_pos) &&
(token_pos <= func.end_token_pos()));
ASSERT(func.is_debuggable());
function_ = func.raw();
token_pos_ = token_pos;
end_token_pos_ = token_pos;
@ -1565,12 +1566,12 @@ void Debugger::FindCompiledFunctions(const Script& script,
if ((function.token_pos() == start_pos)
&& (function.end_token_pos() == end_pos)
&& (function.script() == script.raw())) {
if (function.HasCode() && !function.IsAsyncFunction()) {
if (function.HasCode() && function.is_debuggable()) {
function_list->Add(function);
}
if (function.HasImplicitClosureFunction()) {
function = function.ImplicitClosureFunction();
if (function.HasCode() && !function.IsAsyncFunction()) {
if (function.HasCode() && function.is_debuggable()) {
function_list->Add(function);
}
}
@ -1586,12 +1587,12 @@ void Debugger::FindCompiledFunctions(const Script& script,
if ((function.token_pos() == start_pos)
&& (function.end_token_pos() == end_pos)
&& (function.script() == script.raw())) {
if (function.HasCode() && !function.IsAsyncFunction()) {
if (function.HasCode() && function.is_debuggable()) {
function_list->Add(function);
}
if (function.HasImplicitClosureFunction()) {
function = function.ImplicitClosureFunction();
if (function.HasCode() && !function.IsAsyncFunction()) {
if (function.HasCode() && function.is_debuggable()) {
function_list->Add(function);
}
}
@ -1603,22 +1604,6 @@ void Debugger::FindCompiledFunctions(const Script& script,
}
static bool IsDebuggableFunctionKind(const Function& func) {
RawFunction::Kind kind = func.kind();
if ((kind == RawFunction::kImplicitGetter) ||
(kind == RawFunction::kImplicitSetter) ||
(kind == RawFunction::kImplicitStaticFinalGetter) ||
(kind == RawFunction::kMethodExtractor) ||
(kind == RawFunction::kNoSuchMethodDispatcher) ||
(kind == RawFunction::kInvokeFieldDispatcher) ||
(kind == RawFunction::kIrregexpFunction) ||
func.IsImplicitConstructor()) {
return false;
}
return true;
}
static void SelectBestFit(Function* best_fit, Function* func) {
if (best_fit->IsNull()) {
*best_fit = func->raw();
@ -1661,7 +1646,7 @@ RawFunction* Debugger::FindBestFit(const Script& script,
for (intptr_t pos = 0; pos < num_functions; pos++) {
function ^= functions.At(pos);
ASSERT(!function.IsNull());
if (IsDebuggableFunctionKind(function) &&
if (function.is_debuggable() &&
FunctionContains(function, script, token_pos)) {
SelectBestFit(&best_fit, &function);
}
@ -1674,7 +1659,7 @@ RawFunction* Debugger::FindBestFit(const Script& script,
for (intptr_t pos = 0; pos < num_closures; pos++) {
function ^= closures.At(pos);
ASSERT(!function.IsNull());
if (IsDebuggableFunctionKind(function) &&
if (function.is_debuggable() &&
FunctionContains(function, script, token_pos)) {
SelectBestFit(&best_fit, &function);
}
@ -1792,6 +1777,9 @@ RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) {
SourceBreakpoint* Debugger::SetBreakpointAtEntry(
const Function& target_function) {
ASSERT(!target_function.IsNull());
if (!target_function.is_debuggable()) {
return NULL;
}
const Script& script = Script::Handle(target_function.script());
return SetBreakpoint(script,
target_function.token_pos(),
@ -2134,7 +2122,7 @@ void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace) {
// static
bool Debugger::IsDebuggable(const Function& func) {
if (!IsDebuggableFunctionKind(func)) {
if (!func.is_debuggable()) {
return false;
}
if (Service::IsRunning()) {
@ -2298,7 +2286,8 @@ RawFunction* Debugger::FindInnermostClosure(const Function& function,
Function& best_fit = Function::Handle(isolate_);
for (intptr_t i = 0; i < num_closures; i++) {
closure ^= closures.At(i);
if ((function.token_pos() < closure.token_pos()) &&
if (closure.is_debuggable() &&
(function.token_pos() < closure.token_pos()) &&
(closure.end_token_pos() < function.end_token_pos()) &&
(closure.token_pos() <= token_pos) &&
(token_pos <= closure.end_token_pos()) &&
@ -2315,6 +2304,12 @@ void Debugger::NotifyCompilation(const Function& func) {
// Return with minimal overhead if there are no breakpoints.
return;
}
if (!func.is_debuggable()) {
// Nothing to do if the function is not debuggable. If there is
// a pending breakpoint in an inner function (that is debuggable),
// we'll resolve the breakpoint when the inner function is compiled.
return;
}
// Iterate over all source breakpoints to check whether breakpoints
// need to be set in the newly compiled function.
Script& script = Script::Handle(isolate_);

View file

@ -67,6 +67,7 @@ void MegamorphicCacheTable::InitMissHandler() {
false, // Not native.
cls,
0)); // No token position.
function.set_is_debuggable(false);
miss_handler_code_ = code.raw();
miss_handler_function_ = function.raw();
function.AttachCode(code);

View file

@ -2669,6 +2669,7 @@ RawFunction* Class::CreateInvocationDispatcher(const String& target_name,
invocation.SetParameterNameAt(i, String::Handle(desc.NameAt(index)));
}
invocation.set_result_type(Type::Handle(Type::DynamicType()));
invocation.set_is_debuggable(false);
invocation.set_is_visible(false); // Not visible in stack trace.
invocation.set_saved_args_desc(args_desc);
@ -6197,6 +6198,7 @@ RawFunction* Function::New(const String& name,
result.set_is_external(is_external);
result.set_is_native(is_native);
result.set_is_visible(true); // Will be computed later.
result.set_is_debuggable(true); // Will be computed later.
result.set_is_intrinsic(false);
result.set_is_redirecting(false);
result.set_is_async_closure(false);
@ -6222,7 +6224,6 @@ RawFunction* Function::New(const String& name,
const ClosureData& data = ClosureData::Handle(ClosureData::New());
result.set_data(data);
}
return result.raw();
}
@ -6297,6 +6298,7 @@ RawFunction* Function::NewEvalFunction(const Class& owner,
owner,
0));
ASSERT(!script.IsNull());
result.set_is_debuggable(false);
result.set_eval_script(script);
return result.raw();
}

View file

@ -2174,6 +2174,7 @@ class Function : public Object {
V(Const, is_const) \
V(Abstract, is_abstract) \
V(Visible, is_visible) \
V(Debuggable, is_debuggable) \
V(Optimizable, is_optimizable) \
V(Inlinable, is_inlinable) \
V(Intrinsic, is_intrinsic) \

View file

@ -944,6 +944,7 @@ RawObject* Parser::ParseMetadata(const Class& cls, intptr_t token_pos) {
false, // is_native
cls,
token_pos));
fake_function.set_is_debuggable(false);
ParsedFunction* parsed_function =
new ParsedFunction(isolate, fake_function);
Parser parser(script, parsed_function, token_pos);
@ -1082,6 +1083,7 @@ ParsedFunction* Parser::ParseStaticFieldInitializer(const Field& field) {
// and inlining them. After the field is initialized, the
// compiler can eliminate the call to the static initializer.
initializer.set_is_visible(false);
initializer.set_is_debuggable(false);
initializer.SetIsOptimizable(false);
initializer.set_is_inlinable(false);
@ -1647,6 +1649,7 @@ void Parser::ParseFormalParameter(bool allow_explicit_default_value,
current_class(),
parameter.name_pos));
signature_function.set_result_type(result_type);
signature_function.set_is_debuggable(false);
AddFormalParamsToFunction(&func_params, signature_function);
const String& signature = String::Handle(I,
signature_function.Signature());
@ -3129,8 +3132,12 @@ SequenceNode* Parser::ParseFunc(const Function& func,
Function& async_closure = Function::ZoneHandle(I);
if (func.IsAsyncFunction() && !func.is_async_closure()) {
// The code of an async function is synthesized. Disable debugging.
func.set_is_debuggable(false);
async_closure = OpenAsyncFunction(func.token_pos());
} else if (func.is_async_closure()) {
// The closure containing the body of an async function is debuggable.
ASSERT(func.is_debuggable());
OpenAsyncClosure();
}
@ -3774,6 +3781,7 @@ void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) {
current_class(),
field->name_pos);
getter.set_result_type(*field->type);
getter.set_is_debuggable(false);
members->AddFunction(getter);
}
}
@ -3794,6 +3802,7 @@ void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) {
ASSERT(current_class().raw() == getter.Owner());
params.AddReceiver(ReceiverType(current_class()), field->name_pos);
getter.set_result_type(*field->type);
getter.set_is_debuggable(false);
AddFormalParamsToFunction(&params, getter);
members->AddFunction(getter);
if (!field->has_final) {
@ -3815,6 +3824,7 @@ void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) {
&Symbols::Value(),
field->type);
setter.set_result_type(Type::Handle(I, Type::VoidType()));
setter.set_is_debuggable(false);
AddFormalParamsToFunction(&params, setter);
members->AddFunction(setter);
}
@ -4414,6 +4424,7 @@ void Parser::ParseEnumDefinition(const Class& cls) {
cls,
cls.token_pos());
getter.set_result_type(int_type);
getter.set_is_debuggable(false);
ParamList params;
params.AddReceiver(&dynamic_type, cls.token_pos());
AddFormalParamsToFunction(&params, getter);
@ -4560,6 +4571,7 @@ void Parser::AddImplicitConstructor(const Class& cls) {
cls,
cls.token_pos()));
ctor.set_end_token_pos(ctor.token_pos());
ctor.set_is_debuggable(false);
if (library_.is_dart_scheme() && library_.IsPrivate(ctor_name)) {
ctor.set_is_visible(false);
}
@ -4796,6 +4808,7 @@ void Parser::ParseTypedef(const GrowableObjectArray& pending_classes,
function_type_alias,
alias_name_pos));
signature_function.set_result_type(result_type);
signature_function.set_is_debuggable(false);
AddFormalParamsToFunction(&func_params, signature_function);
// Patch the signature function in the signature class.
@ -5137,6 +5150,7 @@ void Parser::ParseTopLevelVariable(TopLevel* top_level,
current_class(),
name_pos);
getter.set_result_type(type);
getter.set_is_debuggable(false);
top_level->functions.Add(getter);
}
} else if (is_final) {
@ -5259,8 +5273,11 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level,
func.set_result_type(result_type);
func.set_end_token_pos(function_end_pos);
func.set_modifier(func_modifier);
if (is_native && library_.is_dart_scheme() && library_.IsPrivate(func_name)) {
func.set_is_visible(false);
if (is_native) {
func.set_is_debuggable(false);
if (library_.is_dart_scheme() && library_.IsPrivate(func_name)) {
func.set_is_visible(false);
}
}
AddFormalParamsToFunction(&params, func);
top_level->functions.Add(func);
@ -5399,9 +5416,11 @@ void Parser::ParseTopLevelAccessor(TopLevel* top_level,
func.set_result_type(result_type);
func.set_end_token_pos(accessor_end_pos);
func.set_modifier(func_modifier);
if (is_native && library_.is_dart_scheme() &&
library_.IsPrivate(accessor_name)) {
func.set_is_visible(false);
if (is_native) {
func.set_is_debuggable(false);
if (library_.is_dart_scheme() && library_.IsPrivate(accessor_name)) {
func.set_is_visible(false);
}
}
AddFormalParamsToFunction(&params, func);
top_level->functions.Add(func);

View file

@ -5128,6 +5128,7 @@ static void CreateSpecializedFunction(Isolate* isolate,
fn.set_regexp(regexp);
fn.set_regexp_cid(specialization_cid);
fn.set_is_debuggable(false);
// The function is compiled lazily during the first call.
}

View file

@ -90,6 +90,7 @@ static RawFunction* CreateMethodExtractor(const String& getter_name,
extractor.set_result_type(Type::Handle(Type::DynamicType()));
extractor.set_extracted_method_closure(closure_function);
extractor.set_is_debuggable(false);
owner.AddFunction(extractor);