Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1 | // Copyright 2012 the V8 project authors. All rights reserved. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 5 | #include "src/v8.h" |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 7 | #include "src/compiler.h" |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 8 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 9 | #include "src/ast-numbering.h" |
| 10 | #include "src/ast-this-access-visitor.h" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 11 | #include "src/bootstrapper.h" |
| 12 | #include "src/codegen.h" |
| 13 | #include "src/compilation-cache.h" |
| 14 | #include "src/compiler/pipeline.h" |
| 15 | #include "src/cpu-profiler.h" |
| 16 | #include "src/debug.h" |
| 17 | #include "src/deoptimizer.h" |
| 18 | #include "src/full-codegen.h" |
| 19 | #include "src/gdb-jit.h" |
| 20 | #include "src/hydrogen.h" |
| 21 | #include "src/isolate-inl.h" |
| 22 | #include "src/lithium.h" |
| 23 | #include "src/liveedit.h" |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 24 | #include "src/messages.h" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 25 | #include "src/parser.h" |
| 26 | #include "src/rewriter.h" |
| 27 | #include "src/runtime-profiler.h" |
| 28 | #include "src/scanner-character-streams.h" |
| 29 | #include "src/scopeinfo.h" |
| 30 | #include "src/scopes.h" |
| 31 | #include "src/typing.h" |
| 32 | #include "src/vm-state-inl.h" |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 33 | |
| 34 | namespace v8 { |
| 35 | namespace internal { |
| 36 | |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 37 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 38 | ScriptData::ScriptData(const byte* data, int length) |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 39 | : owns_data_(false), rejected_(false), data_(data), length_(length) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 40 | if (!IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment)) { |
| 41 | byte* copy = NewArray<byte>(length); |
| 42 | DCHECK(IsAligned(reinterpret_cast<intptr_t>(copy), kPointerAlignment)); |
| 43 | CopyBytes(copy, data, length); |
| 44 | data_ = copy; |
| 45 | AcquireDataOwnership(); |
| 46 | } |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 50 | CompilationInfo::CompilationInfo(Handle<Script> script, Zone* zone) |
| 51 | : flags_(kThisHasUses), |
| 52 | script_(script), |
| 53 | source_stream_(NULL), |
| 54 | osr_ast_id_(BailoutId::None()), |
| 55 | parameter_count_(0), |
| 56 | optimization_id_(-1), |
| 57 | ast_value_factory_(NULL), |
| 58 | ast_value_factory_owned_(false), |
| 59 | aborted_due_to_dependency_change_(false) { |
| 60 | Initialize(script->GetIsolate(), BASE, zone); |
| 61 | } |
| 62 | |
| 63 | |
| 64 | CompilationInfo::CompilationInfo(Isolate* isolate, Zone* zone) |
| 65 | : flags_(kThisHasUses), |
| 66 | script_(Handle<Script>::null()), |
| 67 | source_stream_(NULL), |
| 68 | osr_ast_id_(BailoutId::None()), |
| 69 | parameter_count_(0), |
| 70 | optimization_id_(-1), |
| 71 | ast_value_factory_(NULL), |
| 72 | ast_value_factory_owned_(false), |
| 73 | aborted_due_to_dependency_change_(false) { |
| 74 | Initialize(isolate, STUB, zone); |
| 75 | } |
| 76 | |
| 77 | |
| 78 | CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info, |
| 79 | Zone* zone) |
| 80 | : flags_(kLazy | kThisHasUses), |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 81 | shared_info_(shared_info), |
| 82 | script_(Handle<Script>(Script::cast(shared_info->script()))), |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 83 | source_stream_(NULL), |
| 84 | osr_ast_id_(BailoutId::None()), |
| 85 | parameter_count_(0), |
| 86 | optimization_id_(-1), |
| 87 | ast_value_factory_(NULL), |
| 88 | ast_value_factory_owned_(false), |
| 89 | aborted_due_to_dependency_change_(false) { |
| 90 | Initialize(script_->GetIsolate(), BASE, zone); |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 94 | CompilationInfo::CompilationInfo(Handle<JSFunction> closure, Zone* zone) |
| 95 | : flags_(kLazy | kThisHasUses), |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 96 | closure_(closure), |
| 97 | shared_info_(Handle<SharedFunctionInfo>(closure->shared())), |
| 98 | script_(Handle<Script>(Script::cast(shared_info_->script()))), |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 99 | source_stream_(NULL), |
| 100 | context_(closure->context()), |
| 101 | osr_ast_id_(BailoutId::None()), |
| 102 | parameter_count_(0), |
| 103 | optimization_id_(-1), |
| 104 | ast_value_factory_(NULL), |
| 105 | ast_value_factory_owned_(false), |
| 106 | aborted_due_to_dependency_change_(false) { |
| 107 | Initialize(script_->GetIsolate(), BASE, zone); |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 111 | CompilationInfo::CompilationInfo(HydrogenCodeStub* stub, Isolate* isolate, |
| 112 | Zone* zone) |
| 113 | : flags_(kLazy | kThisHasUses), |
| 114 | source_stream_(NULL), |
| 115 | osr_ast_id_(BailoutId::None()), |
| 116 | parameter_count_(0), |
| 117 | optimization_id_(-1), |
| 118 | ast_value_factory_(NULL), |
| 119 | ast_value_factory_owned_(false), |
| 120 | aborted_due_to_dependency_change_(false) { |
| 121 | Initialize(isolate, STUB, zone); |
| 122 | code_stub_ = stub; |
| 123 | } |
| 124 | |
| 125 | |
| 126 | CompilationInfo::CompilationInfo( |
| 127 | ScriptCompiler::ExternalSourceStream* stream, |
| 128 | ScriptCompiler::StreamedSource::Encoding encoding, Isolate* isolate, |
| 129 | Zone* zone) |
| 130 | : flags_(kThisHasUses), |
| 131 | source_stream_(stream), |
| 132 | source_stream_encoding_(encoding), |
| 133 | osr_ast_id_(BailoutId::None()), |
| 134 | parameter_count_(0), |
| 135 | optimization_id_(-1), |
| 136 | ast_value_factory_(NULL), |
| 137 | ast_value_factory_owned_(false), |
| 138 | aborted_due_to_dependency_change_(false) { |
| 139 | Initialize(isolate, BASE, zone); |
| 140 | } |
| 141 | |
| 142 | |
| 143 | void CompilationInfo::Initialize(Isolate* isolate, |
| 144 | Mode mode, |
| 145 | Zone* zone) { |
| 146 | isolate_ = isolate; |
| 147 | function_ = NULL; |
| 148 | scope_ = NULL; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 149 | script_scope_ = NULL; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 150 | extension_ = NULL; |
| 151 | cached_data_ = NULL; |
| 152 | compile_options_ = ScriptCompiler::kNoCompileOptions; |
| 153 | zone_ = zone; |
| 154 | deferred_handles_ = NULL; |
| 155 | code_stub_ = NULL; |
| 156 | prologue_offset_ = Code::kPrologueOffsetNotSet; |
| 157 | opt_count_ = shared_info().is_null() ? 0 : shared_info()->opt_count(); |
| 158 | no_frame_ranges_ = isolate->cpu_profiler()->is_profiling() |
| 159 | ? new List<OffsetRange>(2) : NULL; |
| 160 | for (int i = 0; i < DependentCode::kGroupCount; i++) { |
| 161 | dependencies_[i] = NULL; |
| 162 | } |
| 163 | if (mode == STUB) { |
| 164 | mode_ = STUB; |
| 165 | return; |
| 166 | } |
| 167 | mode_ = mode; |
| 168 | if (!script_.is_null() && script_->type()->value() == Script::TYPE_NATIVE) { |
| 169 | MarkAsNative(); |
| 170 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 171 | // Compiling for the snapshot typically results in different code than |
| 172 | // compiling later on. This means that code recompiled with deoptimization |
| 173 | // support won't be "equivalent" (as defined by SharedFunctionInfo:: |
| 174 | // EnableDeoptimizationSupport), so it will replace the old code and all |
| 175 | // its type feedback. To avoid this, always compile functions in the snapshot |
| 176 | // with deoptimization support. |
| 177 | if (isolate_->serializer_enabled()) EnableDeoptimizationSupport(); |
| 178 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 179 | if (isolate_->debug()->is_active()) MarkAsDebug(); |
| 180 | if (FLAG_context_specialization) MarkAsContextSpecializing(); |
| 181 | if (FLAG_turbo_inlining) MarkAsInliningEnabled(); |
| 182 | if (FLAG_turbo_types) MarkAsTypingEnabled(); |
| 183 | |
| 184 | if (!shared_info_.is_null()) { |
| 185 | DCHECK(strict_mode() == SLOPPY); |
| 186 | SetStrictMode(shared_info_->strict_mode()); |
| 187 | } |
| 188 | bailout_reason_ = kUnknown; |
| 189 | |
| 190 | if (!shared_info().is_null() && shared_info()->is_compiled()) { |
| 191 | // We should initialize the CompilationInfo feedback vector from the |
| 192 | // passed in shared info, rather than creating a new one. |
| 193 | feedback_vector_ = |
| 194 | Handle<TypeFeedbackVector>(shared_info()->feedback_vector(), isolate); |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | |
| 199 | CompilationInfo::~CompilationInfo() { |
| 200 | if (GetFlag(kDisableFutureOptimization)) { |
| 201 | shared_info()->DisableOptimization(bailout_reason()); |
| 202 | } |
| 203 | delete deferred_handles_; |
| 204 | delete no_frame_ranges_; |
| 205 | if (ast_value_factory_owned_) delete ast_value_factory_; |
| 206 | #ifdef DEBUG |
| 207 | // Check that no dependent maps have been added or added dependent maps have |
| 208 | // been rolled back or committed. |
| 209 | for (int i = 0; i < DependentCode::kGroupCount; i++) { |
| 210 | DCHECK_EQ(NULL, dependencies_[i]); |
| 211 | } |
| 212 | #endif // DEBUG |
| 213 | } |
| 214 | |
| 215 | |
| 216 | void CompilationInfo::CommitDependencies(Handle<Code> code) { |
| 217 | for (int i = 0; i < DependentCode::kGroupCount; i++) { |
| 218 | ZoneList<Handle<HeapObject> >* group_objects = dependencies_[i]; |
| 219 | if (group_objects == NULL) continue; |
| 220 | DCHECK(!object_wrapper_.is_null()); |
| 221 | for (int j = 0; j < group_objects->length(); j++) { |
| 222 | DependentCode::DependencyGroup group = |
| 223 | static_cast<DependentCode::DependencyGroup>(i); |
| 224 | DependentCode* dependent_code = |
| 225 | DependentCode::ForObject(group_objects->at(j), group); |
| 226 | dependent_code->UpdateToFinishedCode(group, this, *code); |
| 227 | } |
| 228 | dependencies_[i] = NULL; // Zone-allocated, no need to delete. |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | |
| 233 | void CompilationInfo::RollbackDependencies() { |
| 234 | // Unregister from all dependent maps if not yet committed. |
| 235 | for (int i = 0; i < DependentCode::kGroupCount; i++) { |
| 236 | ZoneList<Handle<HeapObject> >* group_objects = dependencies_[i]; |
| 237 | if (group_objects == NULL) continue; |
| 238 | for (int j = 0; j < group_objects->length(); j++) { |
| 239 | DependentCode::DependencyGroup group = |
| 240 | static_cast<DependentCode::DependencyGroup>(i); |
| 241 | DependentCode* dependent_code = |
| 242 | DependentCode::ForObject(group_objects->at(j), group); |
| 243 | dependent_code->RemoveCompilationInfo(group, this); |
| 244 | } |
| 245 | dependencies_[i] = NULL; // Zone-allocated, no need to delete. |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | |
| 250 | int CompilationInfo::num_parameters() const { |
| 251 | if (IsStub()) { |
| 252 | DCHECK(parameter_count_ > 0); |
| 253 | return parameter_count_; |
| 254 | } else { |
| 255 | return scope()->num_parameters(); |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | |
| 260 | int CompilationInfo::num_heap_slots() const { |
| 261 | if (IsStub()) { |
| 262 | return 0; |
| 263 | } else { |
| 264 | return scope()->num_heap_slots(); |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | |
| 269 | Code::Flags CompilationInfo::flags() const { |
| 270 | if (IsStub()) { |
| 271 | return Code::ComputeFlags(code_stub()->GetCodeKind(), |
| 272 | code_stub()->GetICState(), |
| 273 | code_stub()->GetExtraICState(), |
| 274 | code_stub()->GetStubType()); |
| 275 | } else { |
| 276 | return Code::ComputeFlags(Code::OPTIMIZED_FUNCTION); |
| 277 | } |
Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 278 | } |
Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 279 | |
Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 280 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 281 | // Primitive functions are unlikely to be picked up by the stack-walking |
| 282 | // profiler, so they trigger their own optimization when they're called |
| 283 | // for the SharedFunctionInfo::kCallsUntilPrimitiveOptimization-th time. |
| 284 | bool CompilationInfo::ShouldSelfOptimize() { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 285 | return FLAG_crankshaft && |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 286 | !function()->flags()->Contains(kDontSelfOptimize) && |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 287 | !function()->dont_optimize() && |
| 288 | function()->scope()->AllowsLazyCompilation() && |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 289 | (shared_info().is_null() || !shared_info()->optimization_disabled()); |
| 290 | } |
| 291 | |
| 292 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 293 | void CompilationInfo::PrepareForCompilation(Scope* scope) { |
| 294 | DCHECK(scope_ == NULL); |
| 295 | scope_ = scope; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 296 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 297 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 298 | |
| 299 | void CompilationInfo::EnsureFeedbackVector() { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 300 | if (feedback_vector_.is_null()) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 301 | feedback_vector_ = isolate()->factory()->NewTypeFeedbackVector( |
| 302 | function()->feedback_vector_spec()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 303 | } |
Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 304 | } |
| 305 | |
| 306 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 307 | class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder { |
| 308 | public: |
| 309 | explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info) |
| 310 | : HOptimizedGraphBuilder(info) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 311 | } |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 312 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 313 | #define DEF_VISIT(type) \ |
| 314 | void Visit##type(type* node) OVERRIDE { \ |
| 315 | if (node->position() != RelocInfo::kNoPosition) { \ |
| 316 | SetSourcePosition(node->position()); \ |
| 317 | } \ |
| 318 | HOptimizedGraphBuilder::Visit##type(node); \ |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 319 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 320 | EXPRESSION_NODE_LIST(DEF_VISIT) |
| 321 | #undef DEF_VISIT |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 322 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 323 | #define DEF_VISIT(type) \ |
| 324 | void Visit##type(type* node) OVERRIDE { \ |
| 325 | if (node->position() != RelocInfo::kNoPosition) { \ |
| 326 | SetSourcePosition(node->position()); \ |
| 327 | } \ |
| 328 | HOptimizedGraphBuilder::Visit##type(node); \ |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 329 | } |
| 330 | STATEMENT_NODE_LIST(DEF_VISIT) |
| 331 | #undef DEF_VISIT |
| 332 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 333 | #define DEF_VISIT(type) \ |
| 334 | void Visit##type(type* node) OVERRIDE { \ |
| 335 | HOptimizedGraphBuilder::Visit##type(node); \ |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 336 | } |
| 337 | MODULE_NODE_LIST(DEF_VISIT) |
| 338 | DECLARATION_NODE_LIST(DEF_VISIT) |
| 339 | #undef DEF_VISIT |
| 340 | }; |
| 341 | |
| 342 | |
| 343 | OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 344 | DCHECK(info()->IsOptimizing()); |
| 345 | DCHECK(!info()->IsCompilingForDebugging()); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 346 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 347 | // Optimization could have been disabled by the parser. |
| 348 | if (info()->shared_info()->optimization_disabled()) { |
| 349 | return AbortOptimization( |
| 350 | info()->shared_info()->disable_optimization_reason()); |
| 351 | } |
Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 352 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 353 | // Do not use crankshaft if we need to be able to set break points. |
| 354 | if (isolate()->DebuggerHasBreakPoints()) { |
| 355 | return RetryOptimization(kDebuggerHasBreakPoints); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 356 | } |
| 357 | |
| 358 | // Limit the number of times we re-compile a functions with |
| 359 | // the optimizing compiler. |
Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 360 | const int kMaxOptCount = |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 361 | FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000; |
| 362 | if (info()->opt_count() > kMaxOptCount) { |
| 363 | return AbortOptimization(kOptimizedTooManyTimes); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 364 | } |
| 365 | |
| 366 | // Due to an encoding limit on LUnallocated operands in the Lithium |
| 367 | // language, we cannot optimize functions with too many formal parameters |
| 368 | // or perform on-stack replacement for function with too many |
| 369 | // stack-allocated local variables. |
| 370 | // |
Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 371 | // The encoding is as a signed value, with parameters and receiver using |
| 372 | // the negative indices and locals the non-negative ones. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 373 | const int parameter_limit = -LUnallocated::kMinFixedSlotIndex; |
| 374 | Scope* scope = info()->scope(); |
| 375 | if ((scope->num_parameters() + 1) > parameter_limit) { |
| 376 | return AbortOptimization(kTooManyParameters); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 377 | } |
| 378 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 379 | const int locals_limit = LUnallocated::kMaxFixedSlotIndex; |
| 380 | if (info()->is_osr() && |
| 381 | scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) { |
| 382 | return AbortOptimization(kTooManyParametersLocals); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 383 | } |
| 384 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 385 | if (scope->HasIllegalRedeclaration()) { |
| 386 | return AbortOptimization(kFunctionWithIllegalRedeclaration); |
| 387 | } |
| 388 | |
| 389 | // Check the whitelist for Crankshaft. |
| 390 | if (!info()->closure()->PassesFilter(FLAG_hydrogen_filter)) { |
| 391 | return AbortOptimization(kHydrogenFilter); |
| 392 | } |
| 393 | |
| 394 | // Crankshaft requires a version of fullcode with deoptimization support. |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 395 | // Recompile the unoptimized version of the code if the current version |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 396 | // doesn't have deoptimization support already. |
| 397 | // Otherwise, if we are gathering compilation time and space statistics |
| 398 | // for hydrogen, gather baseline statistics for a fullcode compilation. |
| 399 | bool should_recompile = !info()->shared_info()->has_deoptimization_support(); |
Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 400 | if (should_recompile || FLAG_hydrogen_stats) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 401 | base::ElapsedTimer timer; |
| 402 | if (FLAG_hydrogen_stats) { |
| 403 | timer.Start(); |
| 404 | } |
| 405 | if (!Compiler::EnsureDeoptimizationSupport(info())) { |
| 406 | return SetLastStatus(FAILED); |
| 407 | } |
| 408 | if (FLAG_hydrogen_stats) { |
| 409 | isolate()->GetHStatistics()->IncrementFullCodeGen(timer.Elapsed()); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 410 | } |
| 411 | } |
| 412 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 413 | DCHECK(info()->shared_info()->has_deoptimization_support()); |
| 414 | |
| 415 | // Check the whitelist for TurboFan. |
| 416 | if ((FLAG_turbo_asm && info()->shared_info()->asm_function()) || |
| 417 | info()->closure()->PassesFilter(FLAG_turbo_filter)) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 418 | if (FLAG_trace_opt) { |
| 419 | OFStream os(stdout); |
| 420 | os << "[compiling method " << Brief(*info()->closure()) |
| 421 | << " using TurboFan]" << std::endl; |
| 422 | } |
| 423 | Timer t(this, &time_taken_to_create_graph_); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 424 | compiler::Pipeline pipeline(info()); |
| 425 | pipeline.GenerateCode(); |
| 426 | if (!info()->code().is_null()) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 427 | return SetLastStatus(SUCCEEDED); |
| 428 | } |
| 429 | } |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 430 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 431 | if (FLAG_trace_opt) { |
| 432 | OFStream os(stdout); |
| 433 | os << "[compiling method " << Brief(*info()->closure()) |
| 434 | << " using Crankshaft]" << std::endl; |
| 435 | } |
| 436 | |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 437 | if (FLAG_trace_hydrogen) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 438 | isolate()->GetHTracer()->TraceCompilation(info()); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 439 | } |
| 440 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 441 | // Type-check the function. |
| 442 | AstTyper::Run(info()); |
| 443 | |
| 444 | graph_builder_ = (FLAG_hydrogen_track_positions || FLAG_trace_ic) |
| 445 | ? new(info()->zone()) HOptimizedGraphBuilderWithPositions(info()) |
| 446 | : new(info()->zone()) HOptimizedGraphBuilder(info()); |
| 447 | |
| 448 | Timer t(this, &time_taken_to_create_graph_); |
| 449 | info()->set_this_has_uses(false); |
| 450 | graph_ = graph_builder_->CreateGraph(); |
| 451 | |
| 452 | if (isolate()->has_pending_exception()) { |
| 453 | return SetLastStatus(FAILED); |
Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 454 | } |
| 455 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 456 | if (graph_ == NULL) return SetLastStatus(BAILED_OUT); |
| 457 | |
| 458 | if (info()->HasAbortedDueToDependencyChange()) { |
| 459 | // Dependency has changed during graph creation. Let's try again later. |
| 460 | return RetryOptimization(kBailedOutDueToDependencyChange); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 461 | } |
| 462 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 463 | return SetLastStatus(SUCCEEDED); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 464 | } |
| 465 | |
| 466 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 467 | OptimizedCompileJob::Status OptimizedCompileJob::OptimizeGraph() { |
| 468 | DisallowHeapAllocation no_allocation; |
| 469 | DisallowHandleAllocation no_handles; |
| 470 | DisallowHandleDereference no_deref; |
| 471 | DisallowCodeDependencyChange no_dependency_change; |
Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 472 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 473 | DCHECK(last_status() == SUCCEEDED); |
| 474 | // TODO(turbofan): Currently everything is done in the first phase. |
| 475 | if (!info()->code().is_null()) { |
| 476 | return last_status(); |
Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 477 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 478 | |
| 479 | Timer t(this, &time_taken_to_optimize_); |
| 480 | DCHECK(graph_ != NULL); |
| 481 | BailoutReason bailout_reason = kNoReason; |
| 482 | |
| 483 | if (graph_->Optimize(&bailout_reason)) { |
| 484 | chunk_ = LChunk::NewChunk(graph_); |
| 485 | if (chunk_ != NULL) return SetLastStatus(SUCCEEDED); |
| 486 | } else if (bailout_reason != kNoReason) { |
| 487 | graph_builder_->Bailout(bailout_reason); |
| 488 | } |
| 489 | |
| 490 | return SetLastStatus(BAILED_OUT); |
Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 491 | } |
Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 492 | |
| 493 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 494 | OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() { |
| 495 | DCHECK(last_status() == SUCCEEDED); |
| 496 | // TODO(turbofan): Currently everything is done in the first phase. |
| 497 | if (!info()->code().is_null()) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 498 | if (FLAG_turbo_deoptimization) { |
| 499 | info()->context()->native_context()->AddOptimizedCode(*info()->code()); |
| 500 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 501 | RecordOptimizationStats(); |
| 502 | return last_status(); |
| 503 | } |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 504 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 505 | DCHECK(!info()->HasAbortedDueToDependencyChange()); |
| 506 | DisallowCodeDependencyChange no_dependency_change; |
| 507 | DisallowJavascriptExecution no_js(isolate()); |
| 508 | { // Scope for timer. |
| 509 | Timer timer(this, &time_taken_to_codegen_); |
| 510 | DCHECK(chunk_ != NULL); |
| 511 | DCHECK(graph_ != NULL); |
| 512 | // Deferred handles reference objects that were accessible during |
| 513 | // graph creation. To make sure that we don't encounter inconsistencies |
| 514 | // between graph creation and code generation, we disallow accessing |
| 515 | // objects through deferred handles during the latter, with exceptions. |
| 516 | DisallowDeferredHandleDereference no_deferred_handle_deref; |
| 517 | Handle<Code> optimized_code = chunk_->Codegen(); |
| 518 | if (optimized_code.is_null()) { |
| 519 | if (info()->bailout_reason() == kNoReason) { |
| 520 | return AbortOptimization(kCodeGenerationFailed); |
Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 521 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 522 | return SetLastStatus(BAILED_OUT); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 523 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 524 | info()->SetCode(optimized_code); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 525 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 526 | RecordOptimizationStats(); |
| 527 | // Add to the weak list of optimized code objects. |
| 528 | info()->context()->native_context()->AddOptimizedCode(*info()->code()); |
| 529 | return SetLastStatus(SUCCEEDED); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 530 | } |
| 531 | |
| 532 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 533 | void OptimizedCompileJob::RecordOptimizationStats() { |
| 534 | Handle<JSFunction> function = info()->closure(); |
| 535 | if (!function->IsOptimized()) { |
| 536 | // Concurrent recompilation and OSR may race. Increment only once. |
| 537 | int opt_count = function->shared()->opt_count(); |
| 538 | function->shared()->set_opt_count(opt_count + 1); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 539 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 540 | double ms_creategraph = time_taken_to_create_graph_.InMillisecondsF(); |
| 541 | double ms_optimize = time_taken_to_optimize_.InMillisecondsF(); |
| 542 | double ms_codegen = time_taken_to_codegen_.InMillisecondsF(); |
| 543 | if (FLAG_trace_opt) { |
| 544 | PrintF("[optimizing "); |
| 545 | function->ShortPrint(); |
| 546 | PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize, |
| 547 | ms_codegen); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 548 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 549 | if (FLAG_trace_opt_stats) { |
| 550 | static double compilation_time = 0.0; |
| 551 | static int compiled_functions = 0; |
| 552 | static int code_size = 0; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 553 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 554 | compilation_time += (ms_creategraph + ms_optimize + ms_codegen); |
| 555 | compiled_functions++; |
| 556 | code_size += function->shared()->SourceSize(); |
| 557 | PrintF("Compiled: %d functions with %d byte source size in %fms.\n", |
| 558 | compiled_functions, |
| 559 | code_size, |
| 560 | compilation_time); |
| 561 | } |
| 562 | if (FLAG_hydrogen_stats) { |
| 563 | isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_create_graph_, |
| 564 | time_taken_to_optimize_, |
| 565 | time_taken_to_codegen_); |
| 566 | } |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 567 | } |
| 568 | |
| 569 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 570 | // Sets the expected number of properties based on estimate from compiler. |
| 571 | void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared, |
| 572 | int estimate) { |
| 573 | // If no properties are added in the constructor, they are more likely |
| 574 | // to be added later. |
| 575 | if (estimate == 0) estimate = 2; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 576 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 577 | // TODO(yangguo): check whether those heuristics are still up-to-date. |
| 578 | // We do not shrink objects that go into a snapshot (yet), so we adjust |
| 579 | // the estimate conservatively. |
| 580 | if (shared->GetIsolate()->serializer_enabled()) { |
| 581 | estimate += 2; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 582 | } else { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 583 | // Inobject slack tracking will reclaim redundant inobject space later, |
| 584 | // so we can afford to adjust the estimate generously. |
| 585 | estimate += 8; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 586 | } |
| 587 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 588 | shared->set_expected_nof_properties(estimate); |
Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 589 | } |
| 590 | |
| 591 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 592 | static void MaybeDisableOptimization(Handle<SharedFunctionInfo> shared_info, |
| 593 | BailoutReason bailout_reason) { |
| 594 | if (bailout_reason != kNoReason) { |
| 595 | shared_info->DisableOptimization(bailout_reason); |
| 596 | } |
| 597 | } |
| 598 | |
| 599 | |
Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 600 | // Sets the function info on a function. |
| 601 | // The start_position points to the first '(' character after the function name |
| 602 | // in the full script source. When counting characters in the script source the |
| 603 | // the first character is number 0 (not 1). |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 604 | static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info, |
| 605 | FunctionLiteral* lit, |
| 606 | bool is_toplevel, |
| 607 | Handle<Script> script) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 608 | function_info->set_length(lit->parameter_count()); |
| 609 | function_info->set_formal_parameter_count(lit->parameter_count()); |
Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 610 | function_info->set_script(*script); |
| 611 | function_info->set_function_token_position(lit->function_token_position()); |
| 612 | function_info->set_start_position(lit->start_position()); |
| 613 | function_info->set_end_position(lit->end_position()); |
| 614 | function_info->set_is_expression(lit->is_expression()); |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 615 | function_info->set_is_anonymous(lit->is_anonymous()); |
Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 616 | function_info->set_is_toplevel(is_toplevel); |
| 617 | function_info->set_inferred_name(*lit->inferred_name()); |
Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 618 | function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 619 | function_info->set_allows_lazy_compilation_without_context( |
| 620 | lit->AllowsLazyCompilationWithoutContext()); |
| 621 | function_info->set_strict_mode(lit->strict_mode()); |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 622 | function_info->set_uses_arguments(lit->scope()->arguments() != NULL); |
| 623 | function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 624 | function_info->set_ast_node_count(lit->ast_node_count()); |
| 625 | function_info->set_is_function(lit->is_function()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 626 | MaybeDisableOptimization(function_info, lit->dont_optimize_reason()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 627 | function_info->set_dont_cache(lit->flags()->Contains(kDontCache)); |
| 628 | function_info->set_kind(lit->kind()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 629 | function_info->set_uses_super_property(lit->uses_super_property()); |
| 630 | function_info->set_uses_super_constructor_call( |
| 631 | lit->uses_super_constructor_call()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 632 | function_info->set_asm_function(lit->scope()->asm_function()); |
Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 633 | } |
| 634 | |
| 635 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 636 | static void RecordFunctionCompilation(Logger::LogEventsAndTags tag, |
| 637 | CompilationInfo* info, |
| 638 | Handle<SharedFunctionInfo> shared) { |
Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 639 | // SharedFunctionInfo is passed separately, because if CompilationInfo |
| 640 | // was created using Script object, it will not have it. |
| 641 | |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 642 | // Log the code generation. If source information is available include |
| 643 | // script name and line number. Check explicitly whether logging is |
| 644 | // enabled as finding the line number is not free. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 645 | if (info->isolate()->logger()->is_logging_code_events() || |
| 646 | info->isolate()->cpu_profiler()->is_profiling()) { |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 647 | Handle<Script> script = info->script(); |
| 648 | Handle<Code> code = info->code(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 649 | if (code.is_identical_to(info->isolate()->builtins()->CompileLazy())) { |
Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 650 | return; |
Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 651 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 652 | int line_num = Script::GetLineNumber(script, shared->start_position()) + 1; |
| 653 | int column_num = |
| 654 | Script::GetColumnNumber(script, shared->start_position()) + 1; |
| 655 | String* script_name = script->name()->IsString() |
| 656 | ? String::cast(script->name()) |
| 657 | : info->isolate()->heap()->empty_string(); |
| 658 | Logger::LogEventsAndTags log_tag = Logger::ToNativeByScript(tag, *script); |
| 659 | PROFILE(info->isolate(), |
| 660 | CodeCreateEvent(log_tag, *code, *shared, info, script_name, |
| 661 | line_num, column_num)); |
Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 662 | } |
Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 663 | |
Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 664 | GDBJIT(AddCode(Handle<String>(shared->DebugName()), |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 665 | Handle<Script>(info->script()), Handle<Code>(info->code()), |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 666 | info)); |
Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 667 | } |
Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 668 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 669 | |
| 670 | static bool CompileUnoptimizedCode(CompilationInfo* info) { |
| 671 | DCHECK(AllowCompilation::IsAllowed(info->isolate())); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 672 | if (!Compiler::Analyze(info) || !FullCodeGenerator::MakeCode(info)) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 673 | Isolate* isolate = info->isolate(); |
| 674 | if (!isolate->has_pending_exception()) isolate->StackOverflow(); |
| 675 | return false; |
| 676 | } |
| 677 | return true; |
| 678 | } |
| 679 | |
| 680 | |
| 681 | MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCodeCommon( |
| 682 | CompilationInfo* info) { |
| 683 | VMState<COMPILER> state(info->isolate()); |
| 684 | PostponeInterruptsScope postpone(info->isolate()); |
| 685 | |
| 686 | // Parse and update CompilationInfo with the results. |
| 687 | if (!Parser::Parse(info)) return MaybeHandle<Code>(); |
| 688 | Handle<SharedFunctionInfo> shared = info->shared_info(); |
| 689 | FunctionLiteral* lit = info->function(); |
| 690 | shared->set_strict_mode(lit->strict_mode()); |
| 691 | SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 692 | MaybeDisableOptimization(shared, lit->dont_optimize_reason()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 693 | |
| 694 | // Compile unoptimized code. |
| 695 | if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>(); |
| 696 | |
| 697 | CHECK_EQ(Code::FUNCTION, info->code()->kind()); |
| 698 | RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared); |
| 699 | |
| 700 | // Update the shared function info with the scope info. Allocating the |
| 701 | // ScopeInfo object may cause a GC. |
| 702 | Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope(), info->zone()); |
| 703 | shared->set_scope_info(*scope_info); |
| 704 | |
| 705 | // Update the code and feedback vector for the shared function info. |
| 706 | shared->ReplaceCode(*info->code()); |
| 707 | if (shared->optimization_disabled()) info->code()->set_optimizable(false); |
| 708 | shared->set_feedback_vector(*info->feedback_vector()); |
| 709 | |
| 710 | return info->code(); |
| 711 | } |
| 712 | |
| 713 | |
| 714 | MUST_USE_RESULT static MaybeHandle<Code> GetCodeFromOptimizedCodeMap( |
| 715 | Handle<JSFunction> function, BailoutId osr_ast_id) { |
| 716 | if (FLAG_cache_optimized_code) { |
| 717 | Handle<SharedFunctionInfo> shared(function->shared()); |
| 718 | // Bound functions are not cached. |
| 719 | if (shared->bound()) return MaybeHandle<Code>(); |
| 720 | DisallowHeapAllocation no_gc; |
| 721 | int index = shared->SearchOptimizedCodeMap( |
| 722 | function->context()->native_context(), osr_ast_id); |
| 723 | if (index > 0) { |
| 724 | if (FLAG_trace_opt) { |
| 725 | PrintF("[found optimized code for "); |
| 726 | function->ShortPrint(); |
| 727 | if (!osr_ast_id.IsNone()) { |
| 728 | PrintF(" at OSR AST id %d", osr_ast_id.ToInt()); |
| 729 | } |
| 730 | PrintF("]\n"); |
| 731 | } |
| 732 | FixedArray* literals = shared->GetLiteralsFromOptimizedCodeMap(index); |
| 733 | if (literals != NULL) function->set_literals(literals); |
| 734 | return Handle<Code>(shared->GetCodeFromOptimizedCodeMap(index)); |
| 735 | } |
| 736 | } |
| 737 | return MaybeHandle<Code>(); |
| 738 | } |
| 739 | |
| 740 | |
| 741 | static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) { |
| 742 | Handle<Code> code = info->code(); |
| 743 | if (code->kind() != Code::OPTIMIZED_FUNCTION) return; // Nothing to do. |
| 744 | |
| 745 | // Context specialization folds-in the context, so no sharing can occur. |
| 746 | if (code->is_turbofanned() && info->is_context_specializing()) return; |
| 747 | |
| 748 | // Cache optimized code. |
| 749 | if (FLAG_cache_optimized_code) { |
| 750 | Handle<JSFunction> function = info->closure(); |
| 751 | Handle<SharedFunctionInfo> shared(function->shared()); |
| 752 | // Do not cache bound functions. |
| 753 | if (shared->bound()) return; |
| 754 | Handle<FixedArray> literals(function->literals()); |
| 755 | Handle<Context> native_context(function->context()->native_context()); |
| 756 | SharedFunctionInfo::AddToOptimizedCodeMap(shared, native_context, code, |
| 757 | literals, info->osr_ast_id()); |
| 758 | } |
| 759 | } |
| 760 | |
| 761 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 762 | static bool Renumber(CompilationInfo* info) { |
| 763 | if (!AstNumbering::Renumber(info->function(), info->zone())) return false; |
| 764 | if (!info->shared_info().is_null()) { |
| 765 | FunctionLiteral* lit = info->function(); |
| 766 | info->shared_info()->set_ast_node_count(lit->ast_node_count()); |
| 767 | MaybeDisableOptimization(info->shared_info(), lit->dont_optimize_reason()); |
| 768 | info->shared_info()->set_dont_cache(lit->flags()->Contains(kDontCache)); |
| 769 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 770 | return true; |
| 771 | } |
| 772 | |
| 773 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 774 | static void ThrowSuperConstructorCheckError(CompilationInfo* info, |
| 775 | Statement* stmt) { |
| 776 | MaybeHandle<Object> obj = info->isolate()->factory()->NewTypeError( |
| 777 | "super_constructor_call", HandleVector<Object>(nullptr, 0)); |
| 778 | Handle<Object> exception; |
| 779 | if (!obj.ToHandle(&exception)) return; |
| 780 | |
| 781 | MessageLocation location(info->script(), stmt->position(), stmt->position()); |
| 782 | USE(info->isolate()->Throw(*exception, &location)); |
| 783 | } |
| 784 | |
| 785 | |
| 786 | static bool CheckSuperConstructorCall(CompilationInfo* info) { |
| 787 | FunctionLiteral* function = info->function(); |
| 788 | if (!function->uses_super_constructor_call()) return true; |
| 789 | |
| 790 | if (function->is_default_constructor()) return true; |
| 791 | |
| 792 | ZoneList<Statement*>* body = function->body(); |
| 793 | CHECK(body->length() > 0); |
| 794 | |
| 795 | int super_call_index = 0; |
| 796 | // Allow 'use strict' and similiar and empty statements. |
| 797 | while (true) { |
| 798 | CHECK(super_call_index < body->length()); // We know there is a super call. |
| 799 | Statement* stmt = body->at(super_call_index); |
| 800 | if (stmt->IsExpressionStatement() && |
| 801 | stmt->AsExpressionStatement()->expression()->IsLiteral()) { |
| 802 | super_call_index++; |
| 803 | continue; |
| 804 | } |
| 805 | if (stmt->IsEmptyStatement()) { |
| 806 | super_call_index++; |
| 807 | continue; |
| 808 | } |
| 809 | break; |
| 810 | } |
| 811 | |
| 812 | Statement* stmt = body->at(super_call_index); |
| 813 | ExpressionStatement* exprStm = stmt->AsExpressionStatement(); |
| 814 | if (exprStm == nullptr) { |
| 815 | ThrowSuperConstructorCheckError(info, stmt); |
| 816 | return false; |
| 817 | } |
| 818 | Call* callExpr = exprStm->expression()->AsCall(); |
| 819 | if (callExpr == nullptr) { |
| 820 | ThrowSuperConstructorCheckError(info, stmt); |
| 821 | return false; |
| 822 | } |
| 823 | |
| 824 | if (!callExpr->expression()->IsSuperReference()) { |
| 825 | ThrowSuperConstructorCheckError(info, stmt); |
| 826 | return false; |
| 827 | } |
| 828 | |
| 829 | ZoneList<Expression*>* arguments = callExpr->arguments(); |
| 830 | |
| 831 | AstThisAccessVisitor this_access_visitor(info->zone()); |
| 832 | this_access_visitor.VisitExpressions(arguments); |
| 833 | |
| 834 | if (this_access_visitor.HasStackOverflow()) return false; |
| 835 | if (this_access_visitor.UsesThis()) { |
| 836 | ThrowSuperConstructorCheckError(info, stmt); |
| 837 | return false; |
| 838 | } |
| 839 | |
| 840 | return true; |
| 841 | } |
| 842 | |
| 843 | |
| 844 | bool Compiler::Analyze(CompilationInfo* info) { |
| 845 | DCHECK(info->function() != NULL); |
| 846 | if (!Rewriter::Rewrite(info)) return false; |
| 847 | if (!Scope::Analyze(info)) return false; |
| 848 | if (!Renumber(info)) return false; |
| 849 | DCHECK(info->scope() != NULL); |
| 850 | if (!CheckSuperConstructorCall(info)) return false; |
| 851 | return true; |
| 852 | } |
| 853 | |
| 854 | |
| 855 | bool Compiler::ParseAndAnalyze(CompilationInfo* info) { |
| 856 | if (!Parser::Parse(info)) return false; |
| 857 | return Compiler::Analyze(info); |
| 858 | } |
| 859 | |
| 860 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 861 | static bool GetOptimizedCodeNow(CompilationInfo* info) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 862 | if (!Compiler::ParseAndAnalyze(info)) return false; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 863 | |
| 864 | TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate()); |
| 865 | |
| 866 | OptimizedCompileJob job(info); |
| 867 | if (job.CreateGraph() != OptimizedCompileJob::SUCCEEDED || |
| 868 | job.OptimizeGraph() != OptimizedCompileJob::SUCCEEDED || |
| 869 | job.GenerateCode() != OptimizedCompileJob::SUCCEEDED) { |
| 870 | if (FLAG_trace_opt) { |
| 871 | PrintF("[aborted optimizing "); |
| 872 | info->closure()->ShortPrint(); |
| 873 | PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason())); |
| 874 | } |
| 875 | return false; |
| 876 | } |
| 877 | |
| 878 | // Success! |
| 879 | DCHECK(!info->isolate()->has_pending_exception()); |
| 880 | InsertCodeIntoOptimizedCodeMap(info); |
| 881 | RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, |
| 882 | info->shared_info()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 883 | return true; |
| 884 | } |
| 885 | |
| 886 | |
| 887 | static bool GetOptimizedCodeLater(CompilationInfo* info) { |
| 888 | Isolate* isolate = info->isolate(); |
| 889 | if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) { |
| 890 | if (FLAG_trace_concurrent_recompilation) { |
| 891 | PrintF(" ** Compilation queue full, will retry optimizing "); |
| 892 | info->closure()->ShortPrint(); |
| 893 | PrintF(" later.\n"); |
| 894 | } |
| 895 | return false; |
| 896 | } |
| 897 | |
| 898 | CompilationHandleScope handle_scope(info); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 899 | if (!Compiler::ParseAndAnalyze(info)) return false; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 900 | info->SaveHandles(); // Copy handles to the compilation handle scope. |
| 901 | |
| 902 | TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate()); |
| 903 | |
| 904 | OptimizedCompileJob* job = new (info->zone()) OptimizedCompileJob(info); |
| 905 | OptimizedCompileJob::Status status = job->CreateGraph(); |
| 906 | if (status != OptimizedCompileJob::SUCCEEDED) return false; |
| 907 | isolate->optimizing_compiler_thread()->QueueForOptimization(job); |
| 908 | |
| 909 | if (FLAG_trace_concurrent_recompilation) { |
| 910 | PrintF(" ** Queued "); |
| 911 | info->closure()->ShortPrint(); |
| 912 | if (info->is_osr()) { |
| 913 | PrintF(" for concurrent OSR at %d.\n", info->osr_ast_id().ToInt()); |
| 914 | } else { |
| 915 | PrintF(" for concurrent optimization.\n"); |
| 916 | } |
| 917 | } |
| 918 | return true; |
| 919 | } |
| 920 | |
| 921 | |
| 922 | MaybeHandle<Code> Compiler::GetUnoptimizedCode(Handle<JSFunction> function) { |
| 923 | DCHECK(!function->GetIsolate()->has_pending_exception()); |
| 924 | DCHECK(!function->is_compiled()); |
| 925 | if (function->shared()->is_compiled()) { |
| 926 | return Handle<Code>(function->shared()->code()); |
| 927 | } |
| 928 | |
| 929 | CompilationInfoWithZone info(function); |
| 930 | Handle<Code> result; |
| 931 | ASSIGN_RETURN_ON_EXCEPTION(info.isolate(), result, |
| 932 | GetUnoptimizedCodeCommon(&info), |
| 933 | Code); |
| 934 | return result; |
| 935 | } |
| 936 | |
| 937 | |
| 938 | MaybeHandle<Code> Compiler::GetLazyCode(Handle<JSFunction> function) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 939 | Isolate* isolate = function->GetIsolate(); |
| 940 | DCHECK(!isolate->has_pending_exception()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 941 | DCHECK(!function->is_compiled()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 942 | // If the debugger is active, do not compile with turbofan unless we can |
| 943 | // deopt from turbofan code. |
| 944 | if (FLAG_turbo_asm && function->shared()->asm_function() && |
| 945 | (FLAG_turbo_deoptimization || !isolate->debug()->is_active())) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 946 | CompilationInfoWithZone info(function); |
| 947 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 948 | VMState<COMPILER> state(isolate); |
| 949 | PostponeInterruptsScope postpone(isolate); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 950 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 951 | info.SetOptimizing(BailoutId::None(), handle(function->shared()->code())); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 952 | info.MarkAsContextSpecializing(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 953 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 954 | if (GetOptimizedCodeNow(&info)) { |
| 955 | DCHECK(function->shared()->is_compiled()); |
| 956 | return info.code(); |
| 957 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 958 | } |
| 959 | |
| 960 | if (function->shared()->is_compiled()) { |
| 961 | return Handle<Code>(function->shared()->code()); |
| 962 | } |
| 963 | |
| 964 | CompilationInfoWithZone info(function); |
| 965 | Handle<Code> result; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 966 | ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCodeCommon(&info), |
| 967 | Code); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 968 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 969 | if (FLAG_always_opt && isolate->use_crankshaft() && |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 970 | !info.shared_info()->optimization_disabled() && |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 971 | !isolate->DebuggerHasBreakPoints()) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 972 | Handle<Code> opt_code; |
| 973 | if (Compiler::GetOptimizedCode( |
| 974 | function, result, |
| 975 | Compiler::NOT_CONCURRENT).ToHandle(&opt_code)) { |
| 976 | result = opt_code; |
| 977 | } |
| 978 | } |
| 979 | |
| 980 | return result; |
| 981 | } |
| 982 | |
| 983 | |
| 984 | MaybeHandle<Code> Compiler::GetUnoptimizedCode( |
| 985 | Handle<SharedFunctionInfo> shared) { |
| 986 | DCHECK(!shared->GetIsolate()->has_pending_exception()); |
| 987 | DCHECK(!shared->is_compiled()); |
| 988 | |
| 989 | CompilationInfoWithZone info(shared); |
| 990 | return GetUnoptimizedCodeCommon(&info); |
| 991 | } |
| 992 | |
| 993 | |
| 994 | bool Compiler::EnsureCompiled(Handle<JSFunction> function, |
| 995 | ClearExceptionFlag flag) { |
| 996 | if (function->is_compiled()) return true; |
| 997 | MaybeHandle<Code> maybe_code = Compiler::GetLazyCode(function); |
| 998 | Handle<Code> code; |
| 999 | if (!maybe_code.ToHandle(&code)) { |
| 1000 | if (flag == CLEAR_EXCEPTION) { |
| 1001 | function->GetIsolate()->clear_pending_exception(); |
| 1002 | } |
| 1003 | return false; |
| 1004 | } |
| 1005 | function->ReplaceCode(*code); |
| 1006 | DCHECK(function->is_compiled()); |
| 1007 | return true; |
| 1008 | } |
| 1009 | |
| 1010 | |
| 1011 | // TODO(turbofan): In the future, unoptimized code with deopt support could |
| 1012 | // be generated lazily once deopt is triggered. |
| 1013 | bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1014 | DCHECK(info->function() != NULL); |
| 1015 | DCHECK(info->scope() != NULL); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1016 | if (!info->shared_info()->has_deoptimization_support()) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1017 | Handle<SharedFunctionInfo> shared = info->shared_info(); |
| 1018 | CompilationInfoWithZone unoptimized(shared); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1019 | // Note that we use the same AST that we will use for generating the |
| 1020 | // optimized code. |
| 1021 | unoptimized.SetFunction(info->function()); |
| 1022 | unoptimized.PrepareForCompilation(info->scope()); |
| 1023 | unoptimized.SetContext(info->context()); |
| 1024 | unoptimized.EnableDeoptimizationSupport(); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1025 | // If the current code has reloc info for serialization, also include |
| 1026 | // reloc info for serialization for the new code, so that deopt support |
| 1027 | // can be added without losing IC state. |
| 1028 | if (shared->code()->kind() == Code::FUNCTION && |
| 1029 | shared->code()->has_reloc_info_for_serialization()) { |
| 1030 | unoptimized.PrepareForSerializing(); |
| 1031 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1032 | if (!FullCodeGenerator::MakeCode(&unoptimized)) return false; |
| 1033 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1034 | shared->EnableDeoptimizationSupport(*unoptimized.code()); |
| 1035 | shared->set_feedback_vector(*unoptimized.feedback_vector()); |
| 1036 | |
| 1037 | // The scope info might not have been set if a lazily compiled |
| 1038 | // function is inlined before being called for the first time. |
| 1039 | if (shared->scope_info() == ScopeInfo::Empty(info->isolate())) { |
| 1040 | Handle<ScopeInfo> target_scope_info = |
| 1041 | ScopeInfo::Create(info->scope(), info->zone()); |
| 1042 | shared->set_scope_info(*target_scope_info); |
| 1043 | } |
| 1044 | |
| 1045 | // The existing unoptimized code was replaced with the new one. |
| 1046 | RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, &unoptimized, shared); |
| 1047 | } |
| 1048 | return true; |
| 1049 | } |
| 1050 | |
| 1051 | |
| 1052 | // Compile full code for debugging. This code will have debug break slots |
| 1053 | // and deoptimization information. Deoptimization information is required |
| 1054 | // in case that an optimized version of this function is still activated on |
| 1055 | // the stack. It will also make sure that the full code is compiled with |
| 1056 | // the same flags as the previous version, that is flags which can change |
| 1057 | // the code generated. The current method of mapping from already compiled |
| 1058 | // full code without debug break slots to full code with debug break slots |
| 1059 | // depends on the generated code is otherwise exactly the same. |
| 1060 | // If compilation fails, just keep the existing code. |
| 1061 | MaybeHandle<Code> Compiler::GetDebugCode(Handle<JSFunction> function) { |
| 1062 | CompilationInfoWithZone info(function); |
| 1063 | Isolate* isolate = info.isolate(); |
| 1064 | VMState<COMPILER> state(isolate); |
| 1065 | |
| 1066 | info.MarkAsDebug(); |
| 1067 | |
| 1068 | DCHECK(!isolate->has_pending_exception()); |
| 1069 | Handle<Code> old_code(function->shared()->code()); |
| 1070 | DCHECK(old_code->kind() == Code::FUNCTION); |
| 1071 | DCHECK(!old_code->has_debug_break_slots()); |
| 1072 | |
| 1073 | info.MarkCompilingForDebugging(); |
| 1074 | if (old_code->is_compiled_optimizable()) { |
| 1075 | info.EnableDeoptimizationSupport(); |
| 1076 | } else { |
| 1077 | info.MarkNonOptimizable(); |
| 1078 | } |
| 1079 | MaybeHandle<Code> maybe_new_code = GetUnoptimizedCodeCommon(&info); |
| 1080 | Handle<Code> new_code; |
| 1081 | if (!maybe_new_code.ToHandle(&new_code)) { |
| 1082 | isolate->clear_pending_exception(); |
| 1083 | } else { |
| 1084 | DCHECK_EQ(old_code->is_compiled_optimizable(), |
| 1085 | new_code->is_compiled_optimizable()); |
| 1086 | } |
| 1087 | return maybe_new_code; |
| 1088 | } |
| 1089 | |
| 1090 | |
| 1091 | void Compiler::CompileForLiveEdit(Handle<Script> script) { |
| 1092 | // TODO(635): support extensions. |
| 1093 | CompilationInfoWithZone info(script); |
| 1094 | PostponeInterruptsScope postpone(info.isolate()); |
| 1095 | VMState<COMPILER> state(info.isolate()); |
| 1096 | |
| 1097 | info.MarkAsGlobal(); |
| 1098 | if (!Parser::Parse(&info)) return; |
| 1099 | |
| 1100 | LiveEditFunctionTracker tracker(info.isolate(), info.function()); |
| 1101 | if (!CompileUnoptimizedCode(&info)) return; |
| 1102 | if (!info.shared_info().is_null()) { |
| 1103 | Handle<ScopeInfo> scope_info = ScopeInfo::Create(info.scope(), |
| 1104 | info.zone()); |
| 1105 | info.shared_info()->set_scope_info(*scope_info); |
| 1106 | } |
| 1107 | tracker.RecordRootFunctionInfo(info.code()); |
| 1108 | } |
| 1109 | |
| 1110 | |
| 1111 | static Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { |
| 1112 | Isolate* isolate = info->isolate(); |
| 1113 | PostponeInterruptsScope postpone(isolate); |
| 1114 | DCHECK(!isolate->native_context().is_null()); |
| 1115 | Handle<Script> script = info->script(); |
| 1116 | |
| 1117 | // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile? |
| 1118 | FixedArray* array = isolate->native_context()->embedder_data(); |
| 1119 | script->set_context_data(array->get(0)); |
| 1120 | |
| 1121 | isolate->debug()->OnBeforeCompile(script); |
| 1122 | |
| 1123 | DCHECK(info->is_eval() || info->is_global()); |
| 1124 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1125 | info->MarkAsToplevel(); |
| 1126 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1127 | Handle<SharedFunctionInfo> result; |
| 1128 | |
| 1129 | { VMState<COMPILER> state(info->isolate()); |
| 1130 | if (info->function() == NULL) { |
| 1131 | // Parse the script if needed (if it's already parsed, function() is |
| 1132 | // non-NULL). |
| 1133 | bool parse_allow_lazy = |
| 1134 | (info->compile_options() == ScriptCompiler::kConsumeParserCache || |
| 1135 | String::cast(script->source())->length() > |
| 1136 | FLAG_min_preparse_length) && |
| 1137 | !Compiler::DebuggerWantsEagerCompilation(info); |
| 1138 | |
| 1139 | if (!parse_allow_lazy && |
| 1140 | (info->compile_options() == ScriptCompiler::kProduceParserCache || |
| 1141 | info->compile_options() == ScriptCompiler::kConsumeParserCache)) { |
| 1142 | // We are going to parse eagerly, but we either 1) have cached data |
| 1143 | // produced by lazy parsing or 2) are asked to generate cached data. |
| 1144 | // Eager parsing cannot benefit from cached data, and producing cached |
| 1145 | // data while parsing eagerly is not implemented. |
| 1146 | info->SetCachedData(NULL, ScriptCompiler::kNoCompileOptions); |
| 1147 | } |
| 1148 | if (!Parser::Parse(info, parse_allow_lazy)) { |
| 1149 | return Handle<SharedFunctionInfo>::null(); |
| 1150 | } |
| 1151 | } |
| 1152 | |
| 1153 | FunctionLiteral* lit = info->function(); |
| 1154 | LiveEditFunctionTracker live_edit_tracker(isolate, lit); |
| 1155 | |
| 1156 | // Measure how long it takes to do the compilation; only take the |
| 1157 | // rest of the function into account to avoid overlap with the |
| 1158 | // parsing statistics. |
| 1159 | HistogramTimer* rate = info->is_eval() |
| 1160 | ? info->isolate()->counters()->compile_eval() |
| 1161 | : info->isolate()->counters()->compile(); |
| 1162 | HistogramTimerScope timer(rate); |
| 1163 | |
| 1164 | // Compile the code. |
| 1165 | if (!CompileUnoptimizedCode(info)) { |
| 1166 | return Handle<SharedFunctionInfo>::null(); |
| 1167 | } |
| 1168 | |
| 1169 | // Allocate function. |
| 1170 | DCHECK(!info->code().is_null()); |
| 1171 | result = isolate->factory()->NewSharedFunctionInfo( |
| 1172 | lit->name(), lit->materialized_literal_count(), lit->kind(), |
| 1173 | info->code(), ScopeInfo::Create(info->scope(), info->zone()), |
| 1174 | info->feedback_vector()); |
| 1175 | |
| 1176 | DCHECK_EQ(RelocInfo::kNoPosition, lit->function_token_position()); |
| 1177 | SetFunctionInfo(result, lit, true, script); |
| 1178 | |
| 1179 | Handle<String> script_name = script->name()->IsString() |
| 1180 | ? Handle<String>(String::cast(script->name())) |
| 1181 | : isolate->factory()->empty_string(); |
| 1182 | Logger::LogEventsAndTags log_tag = info->is_eval() |
| 1183 | ? Logger::EVAL_TAG |
| 1184 | : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script); |
| 1185 | |
| 1186 | PROFILE(isolate, CodeCreateEvent( |
| 1187 | log_tag, *info->code(), *result, info, *script_name)); |
| 1188 | GDBJIT(AddCode(script_name, script, info->code(), info)); |
| 1189 | |
| 1190 | // Hint to the runtime system used when allocating space for initial |
| 1191 | // property space by setting the expected number of properties for |
| 1192 | // the instances of the function. |
| 1193 | SetExpectedNofPropertiesFromEstimate(result, |
| 1194 | lit->expected_property_count()); |
| 1195 | |
| 1196 | if (!script.is_null()) |
| 1197 | script->set_compilation_state(Script::COMPILATION_STATE_COMPILED); |
| 1198 | |
| 1199 | live_edit_tracker.RecordFunctionInfo(result, lit, info->zone()); |
| 1200 | } |
| 1201 | |
| 1202 | isolate->debug()->OnAfterCompile(script); |
| 1203 | |
| 1204 | return result; |
| 1205 | } |
| 1206 | |
| 1207 | |
| 1208 | MaybeHandle<JSFunction> Compiler::GetFunctionFromEval( |
| 1209 | Handle<String> source, Handle<SharedFunctionInfo> outer_info, |
| 1210 | Handle<Context> context, StrictMode strict_mode, |
| 1211 | ParseRestriction restriction, int scope_position) { |
| 1212 | Isolate* isolate = source->GetIsolate(); |
| 1213 | int source_length = source->length(); |
| 1214 | isolate->counters()->total_eval_size()->Increment(source_length); |
| 1215 | isolate->counters()->total_compile_size()->Increment(source_length); |
| 1216 | |
| 1217 | CompilationCache* compilation_cache = isolate->compilation_cache(); |
| 1218 | MaybeHandle<SharedFunctionInfo> maybe_shared_info = |
| 1219 | compilation_cache->LookupEval(source, outer_info, context, strict_mode, |
| 1220 | scope_position); |
| 1221 | Handle<SharedFunctionInfo> shared_info; |
| 1222 | |
| 1223 | if (!maybe_shared_info.ToHandle(&shared_info)) { |
| 1224 | Handle<Script> script = isolate->factory()->NewScript(source); |
| 1225 | CompilationInfoWithZone info(script); |
| 1226 | info.MarkAsEval(); |
| 1227 | if (context->IsNativeContext()) info.MarkAsGlobal(); |
| 1228 | info.SetStrictMode(strict_mode); |
| 1229 | info.SetParseRestriction(restriction); |
| 1230 | info.SetContext(context); |
| 1231 | |
| 1232 | Debug::RecordEvalCaller(script); |
| 1233 | |
| 1234 | shared_info = CompileToplevel(&info); |
| 1235 | |
| 1236 | if (shared_info.is_null()) { |
| 1237 | return MaybeHandle<JSFunction>(); |
| 1238 | } else { |
| 1239 | // Explicitly disable optimization for eval code. We're not yet prepared |
| 1240 | // to handle eval-code in the optimizing compiler. |
| 1241 | shared_info->DisableOptimization(kEval); |
| 1242 | |
| 1243 | // If caller is strict mode, the result must be in strict mode as well. |
| 1244 | DCHECK(strict_mode == SLOPPY || shared_info->strict_mode() == STRICT); |
| 1245 | if (!shared_info->dont_cache()) { |
| 1246 | compilation_cache->PutEval(source, outer_info, context, shared_info, |
| 1247 | scope_position); |
| 1248 | } |
| 1249 | } |
| 1250 | } else if (shared_info->ic_age() != isolate->heap()->global_ic_age()) { |
| 1251 | shared_info->ResetForNewContext(isolate->heap()->global_ic_age()); |
| 1252 | } |
| 1253 | |
| 1254 | return isolate->factory()->NewFunctionFromSharedFunctionInfo( |
| 1255 | shared_info, context, NOT_TENURED); |
| 1256 | } |
| 1257 | |
| 1258 | |
| 1259 | Handle<SharedFunctionInfo> Compiler::CompileScript( |
| 1260 | Handle<String> source, Handle<Object> script_name, int line_offset, |
| 1261 | int column_offset, bool is_shared_cross_origin, Handle<Context> context, |
| 1262 | v8::Extension* extension, ScriptData** cached_data, |
| 1263 | ScriptCompiler::CompileOptions compile_options, NativesFlag natives) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1264 | Isolate* isolate = source->GetIsolate(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1265 | if (compile_options == ScriptCompiler::kNoCompileOptions) { |
| 1266 | cached_data = NULL; |
| 1267 | } else if (compile_options == ScriptCompiler::kProduceParserCache || |
| 1268 | compile_options == ScriptCompiler::kProduceCodeCache) { |
| 1269 | DCHECK(cached_data && !*cached_data); |
| 1270 | DCHECK(extension == NULL); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1271 | DCHECK(!isolate->debug()->is_loaded()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1272 | } else { |
| 1273 | DCHECK(compile_options == ScriptCompiler::kConsumeParserCache || |
| 1274 | compile_options == ScriptCompiler::kConsumeCodeCache); |
| 1275 | DCHECK(cached_data && *cached_data); |
| 1276 | DCHECK(extension == NULL); |
| 1277 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1278 | int source_length = source->length(); |
| 1279 | isolate->counters()->total_load_size()->Increment(source_length); |
| 1280 | isolate->counters()->total_compile_size()->Increment(source_length); |
| 1281 | |
| 1282 | CompilationCache* compilation_cache = isolate->compilation_cache(); |
| 1283 | |
| 1284 | // Do a lookup in the compilation cache but not for extensions. |
| 1285 | MaybeHandle<SharedFunctionInfo> maybe_result; |
| 1286 | Handle<SharedFunctionInfo> result; |
| 1287 | if (extension == NULL) { |
| 1288 | if (FLAG_serialize_toplevel && |
| 1289 | compile_options == ScriptCompiler::kConsumeCodeCache && |
| 1290 | !isolate->debug()->is_loaded()) { |
| 1291 | HistogramTimerScope timer(isolate->counters()->compile_deserialize()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1292 | Handle<SharedFunctionInfo> result; |
| 1293 | if (CodeSerializer::Deserialize(isolate, *cached_data, source) |
| 1294 | .ToHandle(&result)) { |
| 1295 | return result; |
| 1296 | } |
| 1297 | // Deserializer failed. Fall through to compile. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1298 | } else { |
| 1299 | maybe_result = compilation_cache->LookupScript( |
| 1300 | source, script_name, line_offset, column_offset, |
| 1301 | is_shared_cross_origin, context); |
| 1302 | } |
| 1303 | } |
| 1304 | |
| 1305 | base::ElapsedTimer timer; |
| 1306 | if (FLAG_profile_deserialization && FLAG_serialize_toplevel && |
| 1307 | compile_options == ScriptCompiler::kProduceCodeCache) { |
| 1308 | timer.Start(); |
| 1309 | } |
| 1310 | |
| 1311 | if (!maybe_result.ToHandle(&result)) { |
| 1312 | // No cache entry found. Compile the script. |
| 1313 | |
| 1314 | // Create a script object describing the script to be compiled. |
| 1315 | Handle<Script> script = isolate->factory()->NewScript(source); |
| 1316 | if (natives == NATIVES_CODE) { |
| 1317 | script->set_type(Smi::FromInt(Script::TYPE_NATIVE)); |
| 1318 | } |
| 1319 | if (!script_name.is_null()) { |
| 1320 | script->set_name(*script_name); |
| 1321 | script->set_line_offset(Smi::FromInt(line_offset)); |
| 1322 | script->set_column_offset(Smi::FromInt(column_offset)); |
| 1323 | } |
| 1324 | script->set_is_shared_cross_origin(is_shared_cross_origin); |
| 1325 | |
| 1326 | // Compile the function and add it to the cache. |
| 1327 | CompilationInfoWithZone info(script); |
| 1328 | info.MarkAsGlobal(); |
| 1329 | info.SetCachedData(cached_data, compile_options); |
| 1330 | info.SetExtension(extension); |
| 1331 | info.SetContext(context); |
| 1332 | if (FLAG_serialize_toplevel && |
| 1333 | compile_options == ScriptCompiler::kProduceCodeCache) { |
| 1334 | info.PrepareForSerializing(); |
| 1335 | } |
| 1336 | if (FLAG_use_strict) info.SetStrictMode(STRICT); |
| 1337 | |
| 1338 | result = CompileToplevel(&info); |
| 1339 | if (extension == NULL && !result.is_null() && !result->dont_cache()) { |
| 1340 | compilation_cache->PutScript(source, context, result); |
| 1341 | if (FLAG_serialize_toplevel && |
| 1342 | compile_options == ScriptCompiler::kProduceCodeCache) { |
| 1343 | HistogramTimerScope histogram_timer( |
| 1344 | isolate->counters()->compile_serialize()); |
| 1345 | *cached_data = CodeSerializer::Serialize(isolate, result, source); |
| 1346 | if (FLAG_profile_deserialization) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1347 | PrintF("[Compiling and serializing took %0.3f ms]\n", |
| 1348 | timer.Elapsed().InMillisecondsF()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1349 | } |
| 1350 | } |
| 1351 | } |
| 1352 | |
| 1353 | if (result.is_null()) isolate->ReportPendingMessages(); |
| 1354 | } else if (result->ic_age() != isolate->heap()->global_ic_age()) { |
| 1355 | result->ResetForNewContext(isolate->heap()->global_ic_age()); |
| 1356 | } |
| 1357 | return result; |
| 1358 | } |
| 1359 | |
| 1360 | |
| 1361 | Handle<SharedFunctionInfo> Compiler::CompileStreamedScript( |
| 1362 | CompilationInfo* info, int source_length) { |
| 1363 | Isolate* isolate = info->isolate(); |
| 1364 | isolate->counters()->total_load_size()->Increment(source_length); |
| 1365 | isolate->counters()->total_compile_size()->Increment(source_length); |
| 1366 | |
| 1367 | if (FLAG_use_strict) info->SetStrictMode(STRICT); |
| 1368 | // TODO(marja): FLAG_serialize_toplevel is not honoured and won't be; when the |
| 1369 | // real code caching lands, streaming needs to be adapted to use it. |
| 1370 | return CompileToplevel(info); |
| 1371 | } |
| 1372 | |
| 1373 | |
| 1374 | Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo( |
| 1375 | FunctionLiteral* literal, Handle<Script> script, |
| 1376 | CompilationInfo* outer_info) { |
| 1377 | // Precondition: code has been parsed and scopes have been analyzed. |
| 1378 | CompilationInfoWithZone info(script); |
| 1379 | info.SetFunction(literal); |
| 1380 | info.PrepareForCompilation(literal->scope()); |
| 1381 | info.SetStrictMode(literal->scope()->strict_mode()); |
| 1382 | if (outer_info->will_serialize()) info.PrepareForSerializing(); |
| 1383 | |
| 1384 | Isolate* isolate = info.isolate(); |
| 1385 | Factory* factory = isolate->factory(); |
| 1386 | LiveEditFunctionTracker live_edit_tracker(isolate, literal); |
| 1387 | // Determine if the function can be lazily compiled. This is necessary to |
| 1388 | // allow some of our builtin JS files to be lazily compiled. These |
| 1389 | // builtins cannot be handled lazily by the parser, since we have to know |
| 1390 | // if a function uses the special natives syntax, which is something the |
| 1391 | // parser records. |
| 1392 | // If the debugger requests compilation for break points, we cannot be |
| 1393 | // aggressive about lazy compilation, because it might trigger compilation |
| 1394 | // of functions without an outer context when setting a breakpoint through |
| 1395 | // Debug::FindSharedFunctionInfoInScript. |
| 1396 | bool allow_lazy_without_ctx = literal->AllowsLazyCompilationWithoutContext(); |
| 1397 | bool allow_lazy = literal->AllowsLazyCompilation() && |
| 1398 | !DebuggerWantsEagerCompilation(&info, allow_lazy_without_ctx); |
| 1399 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1400 | if (outer_info->is_toplevel() && outer_info->will_serialize()) { |
| 1401 | // Make sure that if the toplevel code (possibly to be serialized), |
| 1402 | // the inner function must be allowed to be compiled lazily. |
| 1403 | // This is necessary to serialize toplevel code without inner functions. |
| 1404 | DCHECK(allow_lazy); |
| 1405 | } |
| 1406 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1407 | // Generate code |
| 1408 | Handle<ScopeInfo> scope_info; |
| 1409 | if (FLAG_lazy && allow_lazy && !literal->is_parenthesized()) { |
| 1410 | Handle<Code> code = isolate->builtins()->CompileLazy(); |
| 1411 | info.SetCode(code); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1412 | // There's no need in theory for a lazy-compiled function to have a type |
| 1413 | // feedback vector, but some parts of the system expect all |
| 1414 | // SharedFunctionInfo instances to have one. The size of the vector depends |
| 1415 | // on how many feedback-needing nodes are in the tree, and when lazily |
| 1416 | // parsing we might not know that, if this function was never parsed before. |
| 1417 | // In that case the vector will be replaced the next time MakeCode is |
| 1418 | // called. |
| 1419 | info.EnsureFeedbackVector(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1420 | scope_info = Handle<ScopeInfo>(ScopeInfo::Empty(isolate)); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1421 | } else if (Renumber(&info) && FullCodeGenerator::MakeCode(&info)) { |
| 1422 | // MakeCode will ensure that the feedback vector is present and |
| 1423 | // appropriately sized. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1424 | DCHECK(!info.code().is_null()); |
| 1425 | scope_info = ScopeInfo::Create(info.scope(), info.zone()); |
| 1426 | } else { |
| 1427 | return Handle<SharedFunctionInfo>::null(); |
| 1428 | } |
| 1429 | |
| 1430 | // Create a shared function info object. |
| 1431 | Handle<SharedFunctionInfo> result = factory->NewSharedFunctionInfo( |
| 1432 | literal->name(), literal->materialized_literal_count(), literal->kind(), |
| 1433 | info.code(), scope_info, info.feedback_vector()); |
| 1434 | SetFunctionInfo(result, literal, false, script); |
| 1435 | RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result); |
| 1436 | result->set_allows_lazy_compilation(allow_lazy); |
| 1437 | result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx); |
| 1438 | |
| 1439 | // Set the expected number of properties for instances and return |
| 1440 | // the resulting function. |
| 1441 | SetExpectedNofPropertiesFromEstimate(result, |
| 1442 | literal->expected_property_count()); |
| 1443 | live_edit_tracker.RecordFunctionInfo(result, literal, info.zone()); |
| 1444 | return result; |
| 1445 | } |
| 1446 | |
| 1447 | |
| 1448 | MaybeHandle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function, |
| 1449 | Handle<Code> current_code, |
| 1450 | ConcurrencyMode mode, |
| 1451 | BailoutId osr_ast_id) { |
| 1452 | Handle<Code> cached_code; |
| 1453 | if (GetCodeFromOptimizedCodeMap( |
| 1454 | function, osr_ast_id).ToHandle(&cached_code)) { |
| 1455 | return cached_code; |
| 1456 | } |
| 1457 | |
| 1458 | SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(function)); |
| 1459 | Isolate* isolate = info->isolate(); |
| 1460 | DCHECK(AllowCompilation::IsAllowed(isolate)); |
| 1461 | VMState<COMPILER> state(isolate); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1462 | DCHECK(isolate->use_crankshaft()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1463 | DCHECK(!isolate->has_pending_exception()); |
| 1464 | PostponeInterruptsScope postpone(isolate); |
| 1465 | |
| 1466 | Handle<SharedFunctionInfo> shared = info->shared_info(); |
| 1467 | if (shared->code()->kind() != Code::FUNCTION || |
| 1468 | ScopeInfo::Empty(isolate) == shared->scope_info()) { |
| 1469 | // The function was never compiled. Compile it unoptimized first. |
| 1470 | // TODO(titzer): reuse the AST and scope info from this compile. |
| 1471 | CompilationInfoWithZone nested(function); |
| 1472 | nested.EnableDeoptimizationSupport(); |
| 1473 | if (!GetUnoptimizedCodeCommon(&nested).ToHandle(¤t_code)) { |
| 1474 | return MaybeHandle<Code>(); |
| 1475 | } |
| 1476 | shared->ReplaceCode(*current_code); |
| 1477 | } |
| 1478 | current_code->set_profiler_ticks(0); |
| 1479 | |
| 1480 | info->SetOptimizing(osr_ast_id, current_code); |
| 1481 | |
| 1482 | if (mode == CONCURRENT) { |
| 1483 | if (GetOptimizedCodeLater(info.get())) { |
| 1484 | info.Detach(); // The background recompile job owns this now. |
| 1485 | return isolate->builtins()->InOptimizationQueue(); |
| 1486 | } |
| 1487 | } else { |
| 1488 | if (GetOptimizedCodeNow(info.get())) return info->code(); |
| 1489 | } |
| 1490 | |
| 1491 | if (isolate->has_pending_exception()) isolate->clear_pending_exception(); |
| 1492 | return MaybeHandle<Code>(); |
| 1493 | } |
| 1494 | |
| 1495 | |
| 1496 | Handle<Code> Compiler::GetConcurrentlyOptimizedCode(OptimizedCompileJob* job) { |
| 1497 | // Take ownership of compilation info. Deleting compilation info |
| 1498 | // also tears down the zone and the recompile job. |
| 1499 | SmartPointer<CompilationInfo> info(job->info()); |
| 1500 | Isolate* isolate = info->isolate(); |
| 1501 | |
| 1502 | VMState<COMPILER> state(isolate); |
| 1503 | TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate()); |
| 1504 | |
| 1505 | Handle<SharedFunctionInfo> shared = info->shared_info(); |
| 1506 | shared->code()->set_profiler_ticks(0); |
| 1507 | |
| 1508 | // 1) Optimization on the concurrent thread may have failed. |
| 1509 | // 2) The function may have already been optimized by OSR. Simply continue. |
| 1510 | // Except when OSR already disabled optimization for some reason. |
| 1511 | // 3) The code may have already been invalidated due to dependency change. |
| 1512 | // 4) Debugger may have been activated. |
| 1513 | // 5) Code generation may have failed. |
| 1514 | if (job->last_status() == OptimizedCompileJob::SUCCEEDED) { |
| 1515 | if (shared->optimization_disabled()) { |
| 1516 | job->RetryOptimization(kOptimizationDisabled); |
| 1517 | } else if (info->HasAbortedDueToDependencyChange()) { |
| 1518 | job->RetryOptimization(kBailedOutDueToDependencyChange); |
| 1519 | } else if (isolate->DebuggerHasBreakPoints()) { |
| 1520 | job->RetryOptimization(kDebuggerHasBreakPoints); |
| 1521 | } else if (job->GenerateCode() == OptimizedCompileJob::SUCCEEDED) { |
| 1522 | RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info.get(), shared); |
| 1523 | if (info->shared_info()->SearchOptimizedCodeMap( |
| 1524 | info->context()->native_context(), info->osr_ast_id()) == -1) { |
| 1525 | InsertCodeIntoOptimizedCodeMap(info.get()); |
| 1526 | } |
| 1527 | if (FLAG_trace_opt) { |
| 1528 | PrintF("[completed optimizing "); |
| 1529 | info->closure()->ShortPrint(); |
| 1530 | PrintF("]\n"); |
| 1531 | } |
| 1532 | return Handle<Code>(*info->code()); |
| 1533 | } |
| 1534 | } |
| 1535 | |
| 1536 | DCHECK(job->last_status() != OptimizedCompileJob::SUCCEEDED); |
| 1537 | if (FLAG_trace_opt) { |
| 1538 | PrintF("[aborted optimizing "); |
| 1539 | info->closure()->ShortPrint(); |
| 1540 | PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason())); |
| 1541 | } |
| 1542 | return Handle<Code>::null(); |
| 1543 | } |
| 1544 | |
| 1545 | |
| 1546 | bool Compiler::DebuggerWantsEagerCompilation(CompilationInfo* info, |
| 1547 | bool allow_lazy_without_ctx) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1548 | if (LiveEditFunctionTracker::IsActive(info->isolate())) return true; |
| 1549 | Debug* debug = info->isolate()->debug(); |
| 1550 | bool debugging = debug->is_active() || debug->has_break_points(); |
| 1551 | return debugging && !allow_lazy_without_ctx; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1552 | } |
| 1553 | |
| 1554 | |
| 1555 | CompilationPhase::CompilationPhase(const char* name, CompilationInfo* info) |
| 1556 | : name_(name), info_(info), zone_(info->isolate()) { |
| 1557 | if (FLAG_hydrogen_stats) { |
| 1558 | info_zone_start_allocation_size_ = info->zone()->allocation_size(); |
| 1559 | timer_.Start(); |
| 1560 | } |
| 1561 | } |
| 1562 | |
| 1563 | |
| 1564 | CompilationPhase::~CompilationPhase() { |
| 1565 | if (FLAG_hydrogen_stats) { |
| 1566 | unsigned size = zone()->allocation_size(); |
| 1567 | size += info_->zone()->allocation_size() - info_zone_start_allocation_size_; |
| 1568 | isolate()->GetHStatistics()->SaveTiming(name_, timer_.Elapsed(), size); |
| 1569 | } |
| 1570 | } |
| 1571 | |
| 1572 | |
| 1573 | bool CompilationPhase::ShouldProduceTraceOutput() const { |
| 1574 | // Trace if the appropriate trace flag is set and the phase name's first |
| 1575 | // character is in the FLAG_trace_phase command line parameter. |
| 1576 | AllowHandleDereference allow_deref; |
| 1577 | bool tracing_on = info()->IsStub() |
| 1578 | ? FLAG_trace_hydrogen_stubs |
| 1579 | : (FLAG_trace_hydrogen && |
| 1580 | info()->closure()->PassesFilter(FLAG_trace_hydrogen_filter)); |
| 1581 | return (tracing_on && |
| 1582 | base::OS::StrChr(const_cast<char*>(FLAG_trace_phase), name_[0]) != NULL); |
| 1583 | } |
| 1584 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1585 | } } // namespace v8::internal |