From: loislo@chromium.org Date: Thu, 5 Sep 2013 13:20:51 +0000 (+0000) Subject: Functions may not be optimized and we would like to know in cpu profiler what was... X-Git-Tag: upstream/4.7.83~12643 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bbd26abedb2d37ca4ce201523146c2dd002833d4;p=platform%2Fupstream%2Fv8.git Functions may not be optimized and we would like to know in cpu profiler what was the reason. Current v8 implementation may disable optimization for a particular function or block it with help of dont_optimize flag. The patch propagates the reason of that to the SharedFunctionInfo where cpu profiler can get it. SharedFunctionInfo is a heap object so I extracted 8 bits from OptsCount for handling bailout reason code. BUG=none TEST=test-profile-generator/BailoutReason R=yangguo@chromium.org Review URL: https://codereview.chromium.org/23817003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16555 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/include/v8-profiler.h b/include/v8-profiler.h index 65a2f9a..d7350db 100644 --- a/include/v8-profiler.h +++ b/include/v8-profiler.h @@ -57,6 +57,11 @@ class V8_EXPORT CpuProfileNode { */ int GetLineNumber() const; + /** Returns bailout reason for the function + * if the optimization was disabled for it. + */ + const char* GetBailoutReason() const; + /** DEPRECATED. Please use GetHitCount instead. * Returns the count of samples where function was currently executing. */ diff --git a/src/api.cc b/src/api.cc index 44a8d47..ad75715 100644 --- a/src/api.cc +++ b/src/api.cc @@ -7255,6 +7255,12 @@ int CpuProfileNode::GetLineNumber() const { } +const char* CpuProfileNode::GetBailoutReason() const { + const i::ProfileNode* node = reinterpret_cast(this); + return node->entry()->bailout_reason(); +} + + double CpuProfileNode::GetSelfSamplesCount() const { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::CpuProfileNode::GetSelfSamplesCount"); diff --git a/src/ast.cc b/src/ast.cc index b966cc3..cbadb75 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -1085,7 +1085,7 @@ CaseClause::CaseClause(Isolate* isolate, #define DONT_OPTIMIZE_NODE(NodeType) \ void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ increase_node_count(); \ - add_flag(kDontOptimize); \ + set_dont_optimize_reason(k##NodeType); \ add_flag(kDontInline); \ add_flag(kDontSelfOptimize); \ } @@ -1097,7 +1097,7 @@ CaseClause::CaseClause(Isolate* isolate, #define DONT_CACHE_NODE(NodeType) \ void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ increase_node_count(); \ - add_flag(kDontOptimize); \ + set_dont_optimize_reason(k##NodeType); \ add_flag(kDontInline); \ add_flag(kDontSelfOptimize); \ add_flag(kDontCache); \ diff --git a/src/ast.h b/src/ast.h index 0f01a3e..d0454fb 100644 --- a/src/ast.h +++ b/src/ast.h @@ -171,7 +171,6 @@ typedef ZoneList > ZoneObjectList; enum AstPropertiesFlag { kDontInline, - kDontOptimize, kDontSelfOptimize, kDontSoftInline, kDontCache @@ -2316,6 +2315,12 @@ class FunctionLiteral V8_FINAL : public Expression { ast_properties_ = *ast_properties; } + bool dont_optimize() { return dont_optimize_reason_ != kNoReason; } + BailoutReason dont_optimize_reason() { return dont_optimize_reason_; } + void set_dont_optimize_reason(BailoutReason reason) { + dont_optimize_reason_ = reason; + } + protected: FunctionLiteral(Isolate* isolate, Handle name, @@ -2335,6 +2340,7 @@ class FunctionLiteral V8_FINAL : public Expression { scope_(scope), body_(body), inferred_name_(isolate->factory()->empty_string()), + dont_optimize_reason_(kNoReason), materialized_literal_count_(materialized_literal_count), expected_property_count_(expected_property_count), handler_count_(handler_count), @@ -2356,6 +2362,7 @@ class FunctionLiteral V8_FINAL : public Expression { ZoneList* body_; Handle inferred_name_; AstProperties ast_properties_; + BailoutReason dont_optimize_reason_; int materialized_literal_count_; int expected_property_count_; @@ -2830,9 +2837,10 @@ private: \ class AstConstructionVisitor BASE_EMBEDDED { public: - AstConstructionVisitor() { } + AstConstructionVisitor() : dont_optimize_reason_(kNoReason) { } AstProperties* ast_properties() { return &properties_; } + BailoutReason dont_optimize_reason() { return dont_optimize_reason_; } private: template friend class AstNodeFactory; @@ -2845,8 +2853,12 @@ class AstConstructionVisitor BASE_EMBEDDED { void increase_node_count() { properties_.add_node_count(1); } void add_flag(AstPropertiesFlag flag) { properties_.flags()->Add(flag); } + void set_dont_optimize_reason(BailoutReason reason) { + dont_optimize_reason_ = reason; + } AstProperties properties_; + BailoutReason dont_optimize_reason_; }; diff --git a/src/compiler.cc b/src/compiler.cc index 2bf012e..a206066 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -230,7 +230,7 @@ bool CompilationInfo::ShouldSelfOptimize() { return FLAG_self_optimization && FLAG_crankshaft && !function()->flags()->Contains(kDontSelfOptimize) && - !function()->flags()->Contains(kDontOptimize) && + !function()->dont_optimize() && function()->scope()->AllowsLazyCompilation() && (shared_info().is_null() || !shared_info()->optimization_disabled()); } @@ -840,7 +840,7 @@ static bool InstallFullCode(CompilationInfo* info) { // Check the function has compiled code. ASSERT(shared->is_compiled()); - shared->set_dont_optimize(lit->flags()->Contains(kDontOptimize)); + shared->set_dont_optimize_reason(lit->dont_optimize_reason()); shared->set_dont_inline(lit->flags()->Contains(kDontInline)); shared->set_ast_node_count(lit->ast_node_count()); @@ -1360,7 +1360,7 @@ void Compiler::SetFunctionInfo(Handle function_info, function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); function_info->set_ast_node_count(lit->ast_node_count()); function_info->set_is_function(lit->is_function()); - function_info->set_dont_optimize(lit->flags()->Contains(kDontOptimize)); + function_info->set_dont_optimize_reason(lit->dont_optimize_reason()); function_info->set_dont_inline(lit->flags()->Contains(kDontInline)); function_info->set_dont_cache(lit->flags()->Contains(kDontCache)); function_info->set_is_generator(lit->is_generator()); diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc index 537ef44..6e93b64 100644 --- a/src/cpu-profiler.cc +++ b/src/cpu-profiler.cc @@ -243,6 +243,8 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, ASSERT(Script::cast(shared->script())); Script* script = Script::cast(shared->script()); rec->entry->set_script_id(script->id()->value()); + rec->entry->set_bailout_reason( + GetBailoutReason(shared->DisableOptimizationReason())); } rec->size = code->ExecutableSize(); rec->shared = shared->address(); @@ -273,6 +275,8 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, rec->entry->set_script_id(script->id()->value()); rec->size = code->ExecutableSize(); rec->shared = shared->address(); + rec->entry->set_bailout_reason( + GetBailoutReason(shared->DisableOptimizationReason())); processor_->Enqueue(evt_rec); } diff --git a/src/full-codegen.cc b/src/full-codegen.cc index f6a36f5..91a5173 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -333,7 +333,7 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) { Code::Flags flags = Code::ComputeFlags(Code::FUNCTION); Handle code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info); code->set_optimizable(info->IsOptimizable() && - !info->function()->flags()->Contains(kDontOptimize) && + !info->function()->dont_optimize() && info->function()->scope()->AllowsLazyCompilation()); cgen.PopulateDeoptimizationData(code); cgen.PopulateTypeFeedbackInfo(code); diff --git a/src/heap.cc b/src/heap.cc index 7be53c5..aaa3d8b 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -3681,7 +3681,7 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) { share->set_function_token_position(0); // All compiler hints default to false or 0. share->set_compiler_hints(0); - share->set_opt_count(0); + share->set_opt_count_and_bailout_reason(0); return share; } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 2692b3f..800f7c5 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -6358,7 +6358,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind, return false; } AstProperties::Flags* flags(function->flags()); - if (flags->Contains(kDontInline) || flags->Contains(kDontOptimize)) { + if (flags->Contains(kDontInline) || function->dont_optimize()) { TraceInline(target, caller, "target contains unsupported syntax [late]"); return false; } diff --git a/src/objects-inl.h b/src/objects-inl.h index ad0512f..cd8426f 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -4606,7 +4606,8 @@ SMI_ACCESSORS(SharedFunctionInfo, function_token_position, kFunctionTokenPositionOffset) SMI_ACCESSORS(SharedFunctionInfo, compiler_hints, kCompilerHintsOffset) -SMI_ACCESSORS(SharedFunctionInfo, opt_count, kOptCountOffset) +SMI_ACCESSORS(SharedFunctionInfo, opt_count_and_bailout_reason, + kOptCountAndBailoutReasonOffset) SMI_ACCESSORS(SharedFunctionInfo, counters, kCountersOffset) #else @@ -4655,7 +4656,9 @@ PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, compiler_hints, kCompilerHintsOffset) -PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, opt_count, kOptCountOffset) +PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, + opt_count_and_bailout_reason, + kOptCountAndBailoutReasonOffset) PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, counters, kCountersOffset) @@ -4902,6 +4905,24 @@ void SharedFunctionInfo::set_opt_reenable_tries(int tries) { } +int SharedFunctionInfo::opt_count() { + return OptCountBits::decode(opt_count_and_bailout_reason()); +} + + +void SharedFunctionInfo::set_opt_count(int opt_count) { + set_opt_count_and_bailout_reason( + OptCountBits::update(opt_count_and_bailout_reason(), opt_count)); +} + + +BailoutReason SharedFunctionInfo::DisableOptimizationReason() { + BailoutReason reason = static_cast( + DisabledOptimizationReasonBits::decode(opt_count_and_bailout_reason())); + return reason; +} + + bool SharedFunctionInfo::has_deoptimization_support() { Code* code = this->code(); return code->kind() == Code::FUNCTION && code->has_deoptimization_support(); diff --git a/src/objects.cc b/src/objects.cc index aaf6483..ca10394 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -32,6 +32,7 @@ #include "arguments.h" #include "bootstrapper.h" #include "codegen.h" +#include "cpu-profiler.h" #include "debug.h" #include "deoptimizer.h" #include "date.h" @@ -40,6 +41,7 @@ #include "full-codegen.h" #include "hydrogen.h" #include "isolate-inl.h" +#include "log.h" #include "objects-inl.h" #include "objects-visiting.h" #include "objects-visiting-inl.h" @@ -9852,12 +9854,16 @@ void SharedFunctionInfo::DisableOptimization(BailoutReason reason) { // non-optimizable if optimization is disabled for the shared // function info. set_optimization_disabled(true); + set_bailout_reason(reason); // Code should be the lazy compilation stub or else unoptimized. If the // latter, disable optimization for the code too. ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN); if (code()->kind() == Code::FUNCTION) { code()->set_optimizable(false); } + PROFILE(Isolate::Current(), + LogExistingFunction(Handle(this), + Handle(code()))); if (FLAG_trace_opt) { PrintF("[disabled optimization for "); ShortPrint(); diff --git a/src/objects.h b/src/objects.h index 2053763..30b1b85 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1121,6 +1121,7 @@ class MaybeObject BASE_EMBEDDED { "Expected property cell in register rbx") \ V(kExpectingAlignmentForCopyBytes, \ "Expecting alignment for CopyBytes") \ + V(kExportDeclaration, "Export declaration") \ V(kExternalStringExpectedButNotFound, \ "external string expected, but not found") \ V(kFailedBailedOutLastTime, "failed/bailed out last time") \ @@ -1140,6 +1141,7 @@ class MaybeObject BASE_EMBEDDED { V(kGlobalFunctionsMustHaveInitialMap, \ "Global functions must have initial map") \ V(kHeapNumberMapRegisterClobbered, "HeapNumberMap register clobbered") \ + V(kImportDeclaration, "Import declaration") \ V(kImproperObjectOnPrototypeChainForStore, \ "improper object on prototype chain for store") \ V(kIndexIsNegative, "Index is negative") \ @@ -1196,6 +1198,12 @@ class MaybeObject BASE_EMBEDDED { V(kLookupVariableInCountOperation, \ "lookup variable in count operation") \ V(kMapIsNoLongerInEax, "Map is no longer in eax") \ + V(kModuleDeclaration, "Module declaration") \ + V(kModuleLiteral, "Module literal") \ + V(kModulePath, "Module path") \ + V(kModuleStatement, "Module statement") \ + V(kModuleVariable, "Module variable") \ + V(kModuleUrl, "Module url") \ V(kNoCasesLeft, "no cases left") \ V(kNoEmptyArraysHereInEmitFastAsciiArrayJoin, \ "No empty arrays here in EmitFastAsciiArrayJoin") \ @@ -1237,7 +1245,7 @@ class MaybeObject BASE_EMBEDDED { V(kRegisterDidNotMatchExpectedRoot, "Register did not match expected root") \ V(kRegisterWasClobbered, "register was clobbered") \ V(kScopedBlock, "ScopedBlock") \ - V(kSharedFunctionInfoLiteral, "SharedFunctionInfoLiteral") \ + V(kSharedFunctionInfoLiteral, "Shared function info literal") \ V(kSmiAdditionOverflow, "Smi addition overflow") \ V(kSmiSubtractionOverflow, "Smi subtraction overflow") \ V(kStackFrameTypesMustMatch, "stack frame types must match") \ @@ -1323,7 +1331,8 @@ class MaybeObject BASE_EMBEDDED { "we should not have an empty lexical context") \ V(kWithStatement, "WithStatement") \ V(kWrongAddressOrValuePassedToRecordWrite, \ - "Wrong address or value passed to RecordWrite") + "Wrong address or value passed to RecordWrite") \ + V(kYield, "Yield") #define ERROR_MESSAGES_CONSTANTS(C, T) C, @@ -6558,6 +6567,8 @@ class SharedFunctionInfo: public HeapObject { // shared function info. void DisableOptimization(BailoutReason reason); + inline BailoutReason DisableOptimizationReason(); + // Lookup the bailout ID and ASSERT that it exists in the non-optimized // code, returns whether it asserted (i.e., always true if assertions are // disabled). @@ -6587,6 +6598,21 @@ class SharedFunctionInfo: public HeapObject { inline void set_counters(int value); inline int counters(); + // Stores opt_count and bailout_reason as bit-fields. + inline void set_opt_count_and_bailout_reason(int value); + inline int opt_count_and_bailout_reason(); + + void set_bailout_reason(BailoutReason reason) { + set_opt_count_and_bailout_reason( + DisabledOptimizationReasonBits::update(opt_count_and_bailout_reason(), + reason)); + } + + void set_dont_optimize_reason(BailoutReason reason) { + set_bailout_reason(reason); + set_dont_optimize(reason != kNoReason); + } + // Source size of this function. int SourceSize(); @@ -6653,8 +6679,10 @@ class SharedFunctionInfo: public HeapObject { kEndPositionOffset + kPointerSize; static const int kCompilerHintsOffset = kFunctionTokenPositionOffset + kPointerSize; - static const int kOptCountOffset = kCompilerHintsOffset + kPointerSize; - static const int kCountersOffset = kOptCountOffset + kPointerSize; + static const int kOptCountAndBailoutReasonOffset = + kCompilerHintsOffset + kPointerSize; + static const int kCountersOffset = + kOptCountAndBailoutReasonOffset + kPointerSize; // Total size. static const int kSize = kCountersOffset + kPointerSize; @@ -6688,9 +6716,11 @@ class SharedFunctionInfo: public HeapObject { static const int kCompilerHintsOffset = kFunctionTokenPositionOffset + kIntSize; - static const int kOptCountOffset = kCompilerHintsOffset + kIntSize; + static const int kOptCountAndBailoutReasonOffset = + kCompilerHintsOffset + kIntSize; - static const int kCountersOffset = kOptCountOffset + kIntSize; + static const int kCountersOffset = + kOptCountAndBailoutReasonOffset + kIntSize; // Total size. static const int kSize = kCountersOffset + kIntSize; @@ -6749,6 +6779,9 @@ class SharedFunctionInfo: public HeapObject { class OptReenableTriesBits: public BitField {}; class ICAgeBits: public BitField {}; + class OptCountBits: public BitField {}; + class DisabledOptimizationReasonBits: public BitField {}; + private: #if V8_HOST_ARCH_32_BIT // On 32 bit platforms, compiler hints is a smi. diff --git a/src/parser.cc b/src/parser.cc index 257f80d..05ae11e 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -687,6 +687,8 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, FunctionLiteral::kNotParenthesized, FunctionLiteral::kNotGenerator); result->set_ast_properties(factory()->visitor()->ast_properties()); + result->set_dont_optimize_reason( + factory()->visitor()->dont_optimize_reason()); } else if (stack_overflow_) { isolate()->StackOverflow(); } @@ -4334,6 +4336,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ? FunctionLiteral::kIsGenerator : FunctionLiteral::kNotGenerator; AstProperties ast_properties; + BailoutReason dont_optimize_reason = kNoReason; // Parse function body. { FunctionState function_state(this, scope, isolate()); top_scope_->SetScopeName(function_name); @@ -4593,6 +4596,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( CHECK_OK); } ast_properties = *factory()->visitor()->ast_properties(); + dont_optimize_reason = factory()->visitor()->dont_optimize_reason(); } if (is_extended_mode()) { @@ -4614,6 +4618,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( generator); function_literal->set_function_token_position(function_token_position); function_literal->set_ast_properties(&ast_properties); + function_literal->set_dont_optimize_reason(dont_optimize_reason); if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal); return function_literal; diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h index 5a984e5..f2feb73 100644 --- a/src/profile-generator-inl.h +++ b/src/profile-generator-inl.h @@ -56,8 +56,8 @@ CodeEntry::CodeEntry(Logger::LogEventsAndTags tag, line_number_(line_number), shared_id_(0), script_id_(v8::Script::kNoScriptId), - no_frame_ranges_(NULL) { -} + no_frame_ranges_(NULL), + bailout_reason_(kEmptyBailoutReason) { } bool CodeEntry::is_js_function_tag(Logger::LogEventsAndTags tag) { @@ -75,8 +75,7 @@ ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry) entry_(entry), self_ticks_(0), children_(CodeEntriesMatch), - id_(tree->next_node_id()) { -} + id_(tree->next_node_id()) { } CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { diff --git a/src/profile-generator.cc b/src/profile-generator.cc index 19090a0..3c11521 100644 --- a/src/profile-generator.cc +++ b/src/profile-generator.cc @@ -133,6 +133,7 @@ size_t StringsStorage::GetUsedMemorySize() const { const char* const CodeEntry::kEmptyNamePrefix = ""; const char* const CodeEntry::kEmptyResourceName = ""; +const char* const CodeEntry::kEmptyBailoutReason = ""; CodeEntry::~CodeEntry() { @@ -210,13 +211,14 @@ ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { void ProfileNode::Print(int indent) { - OS::Print("%5u %*c %s%s %d #%d", + OS::Print("%5u %*c %s%s %d #%d %s", self_ticks_, indent, ' ', entry_->name_prefix(), entry_->name(), entry_->script_id(), - id()); + id(), + entry_->bailout_reason()); if (entry_->resource_name()[0] != '\0') OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); OS::Print("\n"); diff --git a/src/profile-generator.h b/src/profile-generator.h index 70f00de..9ce5f23 100644 --- a/src/profile-generator.h +++ b/src/profile-generator.h @@ -88,6 +88,10 @@ class CodeEntry { INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; } INLINE(int script_id() const) { return script_id_; } INLINE(void set_script_id(int script_id)) { script_id_ = script_id; } + INLINE(void set_bailout_reason(const char* bailout_reason)) { + bailout_reason_ = bailout_reason; + } + INLINE(const char* bailout_reason() const) { return bailout_reason_; } INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag)); @@ -105,6 +109,7 @@ class CodeEntry { static const char* const kEmptyNamePrefix; static const char* const kEmptyResourceName; + static const char* const kEmptyBailoutReason; private: Logger::LogEventsAndTags tag_ : 8; @@ -116,6 +121,7 @@ class CodeEntry { int shared_id_; int script_id_; List* no_frame_ranges_; + const char* bailout_reason_; DISALLOW_COPY_AND_ASSIGN(CodeEntry); }; diff --git a/test/cctest/test-profile-generator.cc b/test/cctest/test-profile-generator.cc index 5dd92b6..c84003f 100644 --- a/test/cctest/test-profile-generator.cc +++ b/test/cctest/test-profile-generator.cc @@ -782,3 +782,49 @@ TEST(LineNumber) { profiler->StopProfiling("LineNumber"); } + + + +TEST(BailoutReason) { + const char* extensions[] = { "v8/profiler" }; + v8::ExtensionConfiguration config(1, extensions); + LocalContext env(&config); + v8::HandleScope hs(env->GetIsolate()); + + v8::CpuProfiler* profiler = env->GetIsolate()->GetCpuProfiler(); + CHECK_EQ(0, profiler->GetProfileCount()); + v8::Handle script = v8::Script::Compile(v8::String::New( + "function TryCatch() {\n" + " try {\n" + " startProfiling();\n" + " } catch (e) { };\n" + "}\n" + "function TryFinally() {\n" + " try {\n" + " TryCatch();\n" + " } finally { };\n" + "}\n" + "TryFinally();\n" + "stopProfiling();")); + script->Run(); + CHECK_EQ(1, profiler->GetProfileCount()); + const v8::CpuProfile* profile = profiler->GetCpuProfile(0); + const v8::CpuProfileNode* current = profile->GetTopDownRoot(); + reinterpret_cast( + const_cast(current))->Print(0); + // The tree should look like this: + // (root) + // (anonymous function) + // kTryFinally + // kTryCatch + current = PickChild(current, i::ProfileGenerator::kAnonymousFunctionName); + CHECK_NE(NULL, const_cast(current)); + + current = PickChild(current, "TryFinally"); + CHECK_NE(NULL, const_cast(current)); + CHECK(!strcmp("TryFinallyStatement", current->GetBailoutReason())); + + current = PickChild(current, "TryCatch"); + CHECK_NE(NULL, const_cast(current)); + CHECK(!strcmp("TryCatchStatement", current->GetBailoutReason())); +}