| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler.h" | 5 #include "src/compiler.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <memory> | 8 #include <memory> |
| 9 | 9 |
| 10 #include "src/asmjs/asm-js.h" | 10 #include "src/asmjs/asm-js.h" |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 #include "src/parsing/rewriter.h" | 33 #include "src/parsing/rewriter.h" |
| 34 #include "src/parsing/scanner-character-streams.h" | 34 #include "src/parsing/scanner-character-streams.h" |
| 35 #include "src/runtime-profiler.h" | 35 #include "src/runtime-profiler.h" |
| 36 #include "src/snapshot/code-serializer.h" | 36 #include "src/snapshot/code-serializer.h" |
| 37 #include "src/vm-state-inl.h" | 37 #include "src/vm-state-inl.h" |
| 38 | 38 |
| 39 namespace v8 { | 39 namespace v8 { |
| 40 namespace internal { | 40 namespace internal { |
| 41 | 41 |
| 42 | 42 |
| 43 #define PARSE_INFO_GETTER(type, name) \ | |
| 44 type CompilationInfo::name() const { \ | |
| 45 CHECK(parse_info()); \ | |
| 46 return parse_info()->name(); \ | |
| 47 } | |
| 48 | |
| 49 | |
| 50 #define PARSE_INFO_GETTER_WITH_DEFAULT(type, name, def) \ | |
| 51 type CompilationInfo::name() const { \ | |
| 52 return parse_info() ? parse_info()->name() : def; \ | |
| 53 } | |
| 54 | |
| 55 | |
| 56 PARSE_INFO_GETTER(Handle<Script>, script) | |
| 57 PARSE_INFO_GETTER(FunctionLiteral*, literal) | |
| 58 PARSE_INFO_GETTER_WITH_DEFAULT(DeclarationScope*, scope, nullptr) | |
| 59 PARSE_INFO_GETTER_WITH_DEFAULT(Handle<Context>, context, | |
| 60 Handle<Context>::null()) | |
| 61 PARSE_INFO_GETTER(Handle<SharedFunctionInfo>, shared_info) | |
| 62 | |
| 63 #undef PARSE_INFO_GETTER | |
| 64 #undef PARSE_INFO_GETTER_WITH_DEFAULT | |
| 65 | 43 |
| 66 // A wrapper around a CompilationInfo that detaches the Handles from | 44 // A wrapper around a CompilationInfo that detaches the Handles from |
| 67 // the underlying DeferredHandleScope and stores them in info_ on | 45 // the underlying DeferredHandleScope and stores them in info_ on |
| 68 // destruction. | 46 // destruction. |
| 69 class CompilationHandleScope final { | 47 class CompilationHandleScope final { |
| 70 public: | 48 public: |
| 71 explicit CompilationHandleScope(CompilationInfo* info) | 49 explicit CompilationHandleScope(CompilationInfo* info) |
| 72 : deferred_(info->isolate()), info_(info) {} | 50 : deferred_(info->isolate()), info_(info) {} |
| 73 ~CompilationHandleScope() { info_->set_deferred_handles(deferred_.Detach()); } | 51 ~CompilationHandleScope() { info_->set_deferred_handles(deferred_.Detach()); } |
| 74 | 52 |
| 75 private: | 53 private: |
| 76 DeferredHandleScope deferred_; | 54 DeferredHandleScope deferred_; |
| 77 CompilationInfo* info_; | 55 CompilationInfo* info_; |
| 78 }; | 56 }; |
| 79 | 57 |
| 80 // Helper that times a scoped region and records the elapsed time. | 58 // Helper that times a scoped region and records the elapsed time. |
| 81 struct ScopedTimer { | 59 struct ScopedTimer { |
| 82 explicit ScopedTimer(base::TimeDelta* location) : location_(location) { | 60 explicit ScopedTimer(base::TimeDelta* location) : location_(location) { |
| 83 DCHECK(location_ != NULL); | 61 DCHECK(location_ != NULL); |
| 84 timer_.Start(); | 62 timer_.Start(); |
| 85 } | 63 } |
| 86 | 64 |
| 87 ~ScopedTimer() { *location_ += timer_.Elapsed(); } | 65 ~ScopedTimer() { *location_ += timer_.Elapsed(); } |
| 88 | 66 |
| 89 base::ElapsedTimer timer_; | 67 base::ElapsedTimer timer_; |
| 90 base::TimeDelta* location_; | 68 base::TimeDelta* location_; |
| 91 }; | 69 }; |
| 92 | 70 |
| 93 // ---------------------------------------------------------------------------- | 71 // ---------------------------------------------------------------------------- |
| 94 // Implementation of CompilationInfo | |
| 95 | |
| 96 bool CompilationInfo::has_shared_info() const { | |
| 97 return parse_info_ && !parse_info_->shared_info().is_null(); | |
| 98 } | |
| 99 | |
| 100 CompilationInfo::CompilationInfo(ParseInfo* parse_info, | |
| 101 Handle<JSFunction> closure) | |
| 102 : CompilationInfo(parse_info, {}, Code::ComputeFlags(Code::FUNCTION), BASE, | |
| 103 parse_info->isolate(), parse_info->zone()) { | |
| 104 closure_ = closure; | |
| 105 | |
| 106 // Compiling for the snapshot typically results in different code than | |
| 107 // compiling later on. This means that code recompiled with deoptimization | |
| 108 // support won't be "equivalent" (as defined by SharedFunctionInfo:: | |
| 109 // EnableDeoptimizationSupport), so it will replace the old code and all | |
| 110 // its type feedback. To avoid this, always compile functions in the snapshot | |
| 111 // with deoptimization support. | |
| 112 if (isolate_->serializer_enabled()) EnableDeoptimizationSupport(); | |
| 113 | |
| 114 if (FLAG_function_context_specialization) MarkAsFunctionContextSpecializing(); | |
| 115 if (FLAG_turbo_inlining) MarkAsInliningEnabled(); | |
| 116 if (FLAG_turbo_source_positions) MarkAsSourcePositionsEnabled(); | |
| 117 if (FLAG_turbo_splitting) MarkAsSplittingEnabled(); | |
| 118 } | |
| 119 | |
| 120 CompilationInfo::CompilationInfo(Vector<const char> debug_name, | |
| 121 Isolate* isolate, Zone* zone, | |
| 122 Code::Flags code_flags) | |
| 123 : CompilationInfo(nullptr, debug_name, code_flags, STUB, isolate, zone) {} | |
| 124 | |
| 125 CompilationInfo::CompilationInfo(ParseInfo* parse_info, | |
| 126 Vector<const char> debug_name, | |
| 127 Code::Flags code_flags, Mode mode, | |
| 128 Isolate* isolate, Zone* zone) | |
| 129 : parse_info_(parse_info), | |
| 130 isolate_(isolate), | |
| 131 flags_(0), | |
| 132 code_flags_(code_flags), | |
| 133 mode_(mode), | |
| 134 osr_ast_id_(BailoutId::None()), | |
| 135 zone_(zone), | |
| 136 deferred_handles_(nullptr), | |
| 137 dependencies_(isolate, zone), | |
| 138 bailout_reason_(kNoReason), | |
| 139 prologue_offset_(Code::kPrologueOffsetNotSet), | |
| 140 track_positions_(FLAG_hydrogen_track_positions || | |
| 141 isolate->is_profiling()), | |
| 142 parameter_count_(0), | |
| 143 optimization_id_(-1), | |
| 144 osr_expr_stack_height_(0), | |
| 145 debug_name_(debug_name) {} | |
| 146 | |
| 147 CompilationInfo::~CompilationInfo() { | |
| 148 if (GetFlag(kDisableFutureOptimization) && has_shared_info()) { | |
| 149 shared_info()->DisableOptimization(bailout_reason()); | |
| 150 } | |
| 151 dependencies()->Rollback(); | |
| 152 delete deferred_handles_; | |
| 153 } | |
| 154 | |
| 155 | |
| 156 int CompilationInfo::num_parameters() const { | |
| 157 return !IsStub() ? scope()->num_parameters() : parameter_count_; | |
| 158 } | |
| 159 | |
| 160 | |
| 161 int CompilationInfo::num_parameters_including_this() const { | |
| 162 return num_parameters() + (is_this_defined() ? 1 : 0); | |
| 163 } | |
| 164 | |
| 165 | |
| 166 bool CompilationInfo::is_this_defined() const { return !IsStub(); } | |
| 167 | |
| 168 | |
| 169 // Primitive functions are unlikely to be picked up by the stack-walking | |
| 170 // profiler, so they trigger their own optimization when they're called | |
| 171 // for the SharedFunctionInfo::kCallsUntilPrimitiveOptimization-th time. | |
| 172 bool CompilationInfo::ShouldSelfOptimize() { | |
| 173 return FLAG_crankshaft && | |
| 174 !(literal()->flags() & AstProperties::kDontSelfOptimize) && | |
| 175 !literal()->dont_optimize() && | |
| 176 literal()->scope()->AllowsLazyCompilation() && | |
| 177 !shared_info()->optimization_disabled(); | |
| 178 } | |
| 179 | |
| 180 void CompilationInfo::ReopenHandlesInNewHandleScope() { | |
| 181 closure_ = Handle<JSFunction>(*closure_); | |
| 182 } | |
| 183 | |
| 184 bool CompilationInfo::has_simple_parameters() { | |
| 185 return scope()->has_simple_parameters(); | |
| 186 } | |
| 187 | |
| 188 std::unique_ptr<char[]> CompilationInfo::GetDebugName() const { | |
| 189 if (parse_info() && parse_info()->literal()) { | |
| 190 AllowHandleDereference allow_deref; | |
| 191 return parse_info()->literal()->debug_name()->ToCString(); | |
| 192 } | |
| 193 if (parse_info() && !parse_info()->shared_info().is_null()) { | |
| 194 return parse_info()->shared_info()->DebugName()->ToCString(); | |
| 195 } | |
| 196 Vector<const char> name_vec = debug_name_; | |
| 197 if (name_vec.is_empty()) name_vec = ArrayVector("unknown"); | |
| 198 std::unique_ptr<char[]> name(new char[name_vec.length() + 1]); | |
| 199 memcpy(name.get(), name_vec.start(), name_vec.length()); | |
| 200 name[name_vec.length()] = '\0'; | |
| 201 return name; | |
| 202 } | |
| 203 | |
| 204 StackFrame::Type CompilationInfo::GetOutputStackFrameType() const { | |
| 205 switch (output_code_kind()) { | |
| 206 case Code::STUB: | |
| 207 case Code::BYTECODE_HANDLER: | |
| 208 case Code::HANDLER: | |
| 209 case Code::BUILTIN: | |
| 210 #define CASE_KIND(kind) case Code::kind: | |
| 211 IC_KIND_LIST(CASE_KIND) | |
| 212 #undef CASE_KIND | |
| 213 return StackFrame::STUB; | |
| 214 case Code::WASM_FUNCTION: | |
| 215 return StackFrame::WASM; | |
| 216 case Code::JS_TO_WASM_FUNCTION: | |
| 217 return StackFrame::JS_TO_WASM; | |
| 218 case Code::WASM_TO_JS_FUNCTION: | |
| 219 return StackFrame::WASM_TO_JS; | |
| 220 default: | |
| 221 UNIMPLEMENTED(); | |
| 222 return StackFrame::NONE; | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 int CompilationInfo::GetDeclareGlobalsFlags() const { | |
| 227 DCHECK(DeclareGlobalsLanguageMode::is_valid(parse_info()->language_mode())); | |
| 228 return DeclareGlobalsEvalFlag::encode(parse_info()->is_eval()) | | |
| 229 DeclareGlobalsNativeFlag::encode(parse_info()->is_native()) | | |
| 230 DeclareGlobalsLanguageMode::encode(parse_info()->language_mode()); | |
| 231 } | |
| 232 | |
| 233 SourcePositionTableBuilder::RecordingMode | |
| 234 CompilationInfo::SourcePositionRecordingMode() const { | |
| 235 return parse_info() && parse_info()->is_native() | |
| 236 ? SourcePositionTableBuilder::OMIT_SOURCE_POSITIONS | |
| 237 : SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS; | |
| 238 } | |
| 239 | |
| 240 bool CompilationInfo::ExpectsJSReceiverAsReceiver() { | |
| 241 return is_sloppy(parse_info()->language_mode()) && !parse_info()->is_native(); | |
| 242 } | |
| 243 | |
| 244 bool CompilationInfo::has_native_context() const { | |
| 245 return !closure().is_null() && (closure()->native_context() != nullptr); | |
| 246 } | |
| 247 | |
| 248 Context* CompilationInfo::native_context() const { | |
| 249 return has_native_context() ? closure()->native_context() : nullptr; | |
| 250 } | |
| 251 | |
| 252 bool CompilationInfo::has_global_object() const { return has_native_context(); } | |
| 253 | |
| 254 JSGlobalObject* CompilationInfo::global_object() const { | |
| 255 return has_global_object() ? native_context()->global_object() : nullptr; | |
| 256 } | |
| 257 | |
| 258 void CompilationInfo::AddInlinedFunction( | |
| 259 Handle<SharedFunctionInfo> inlined_function) { | |
| 260 inlined_functions_.push_back(InlinedFunctionHolder( | |
| 261 inlined_function, handle(inlined_function->code()))); | |
| 262 } | |
| 263 | |
| 264 Code::Kind CompilationInfo::output_code_kind() const { | |
| 265 return Code::ExtractKindFromFlags(code_flags_); | |
| 266 } | |
| 267 | |
| 268 // ---------------------------------------------------------------------------- | |
| 269 // Implementation of CompilationJob | 72 // Implementation of CompilationJob |
| 270 | 73 |
| 271 CompilationJob::Status CompilationJob::PrepareJob() { | 74 CompilationJob::Status CompilationJob::PrepareJob() { |
| 272 DCHECK(ThreadId::Current().Equals(info()->isolate()->thread_id())); | 75 DCHECK(ThreadId::Current().Equals(info()->isolate()->thread_id())); |
| 273 DisallowJavascriptExecution no_js(isolate()); | 76 DisallowJavascriptExecution no_js(isolate()); |
| 274 | 77 |
| 275 if (FLAG_trace_opt && info()->IsOptimizing()) { | 78 if (FLAG_trace_opt && info()->IsOptimizing()) { |
| 276 OFStream os(stdout); | 79 OFStream os(stdout); |
| 277 os << "[compiling method " << Brief(*info()->closure()) << " using " | 80 os << "[compiling method " << Brief(*info()->closure()) << " using " |
| 278 << compiler_name_; | 81 << compiler_name_; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 DisallowCodeDependencyChange no_dependency_change; | 114 DisallowCodeDependencyChange no_dependency_change; |
| 312 DisallowJavascriptExecution no_js(isolate()); | 115 DisallowJavascriptExecution no_js(isolate()); |
| 313 DCHECK(!info()->dependencies()->HasAborted()); | 116 DCHECK(!info()->dependencies()->HasAborted()); |
| 314 | 117 |
| 315 // Delegate to the underlying implementation. | 118 // Delegate to the underlying implementation. |
| 316 DCHECK(state() == State::kReadyToFinalize); | 119 DCHECK(state() == State::kReadyToFinalize); |
| 317 ScopedTimer t(&time_taken_to_finalize_); | 120 ScopedTimer t(&time_taken_to_finalize_); |
| 318 return UpdateState(FinalizeJobImpl(), State::kSucceeded); | 121 return UpdateState(FinalizeJobImpl(), State::kSucceeded); |
| 319 } | 122 } |
| 320 | 123 |
| 124 CompilationJob::Status CompilationJob::RetryOptimization(BailoutReason reason) { |
| 125 DCHECK(info_->IsOptimizing()); |
| 126 info_->RetryOptimization(reason); |
| 127 state_ = State::kFailed; |
| 128 return FAILED; |
| 129 } |
| 130 |
| 131 CompilationJob::Status CompilationJob::AbortOptimization(BailoutReason reason) { |
| 132 DCHECK(info_->IsOptimizing()); |
| 133 info_->AbortOptimization(reason); |
| 134 state_ = State::kFailed; |
| 135 return FAILED; |
| 136 } |
| 137 |
| 321 void CompilationJob::RecordUnoptimizedCompilationStats() const { | 138 void CompilationJob::RecordUnoptimizedCompilationStats() const { |
| 322 int code_size; | 139 int code_size; |
| 323 if (info()->has_bytecode_array()) { | 140 if (info()->has_bytecode_array()) { |
| 324 code_size = info()->bytecode_array()->SizeIncludingMetadata(); | 141 code_size = info()->bytecode_array()->SizeIncludingMetadata(); |
| 325 } else { | 142 } else { |
| 326 code_size = info()->code()->SizeIncludingMetadata(); | 143 code_size = info()->code()->SizeIncludingMetadata(); |
| 327 } | 144 } |
| 328 | 145 |
| 329 Counters* counters = isolate()->counters(); | 146 Counters* counters = isolate()->counters(); |
| 330 // TODO(4280): Rename counters from "baseline" to "unoptimized" eventually. | 147 // TODO(4280): Rename counters from "baseline" to "unoptimized" eventually. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 PrintF("Compiled: %d functions with %d byte source size in %fms.\n", | 179 PrintF("Compiled: %d functions with %d byte source size in %fms.\n", |
| 363 compiled_functions, code_size, compilation_time); | 180 compiled_functions, code_size, compilation_time); |
| 364 } | 181 } |
| 365 if (FLAG_hydrogen_stats) { | 182 if (FLAG_hydrogen_stats) { |
| 366 isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_prepare_, | 183 isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_prepare_, |
| 367 time_taken_to_execute_, | 184 time_taken_to_execute_, |
| 368 time_taken_to_finalize_); | 185 time_taken_to_finalize_); |
| 369 } | 186 } |
| 370 } | 187 } |
| 371 | 188 |
| 189 Isolate* CompilationJob::isolate() const { return info()->isolate(); } |
| 190 |
| 372 namespace { | 191 namespace { |
| 373 | 192 |
| 374 void AddWeakObjectToCodeDependency(Isolate* isolate, Handle<HeapObject> object, | 193 void AddWeakObjectToCodeDependency(Isolate* isolate, Handle<HeapObject> object, |
| 375 Handle<Code> code) { | 194 Handle<Code> code) { |
| 376 Handle<WeakCell> cell = Code::WeakCellFor(code); | 195 Handle<WeakCell> cell = Code::WeakCellFor(code); |
| 377 Heap* heap = isolate->heap(); | 196 Heap* heap = isolate->heap(); |
| 378 if (heap->InNewSpace(*object)) { | 197 if (heap->InNewSpace(*object)) { |
| 379 heap->AddWeakNewSpaceObjectToCodeDependency(object, cell); | 198 heap->AddWeakNewSpaceObjectToCodeDependency(object, cell); |
| 380 } else { | 199 } else { |
| 381 Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(object)); | 200 Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(object)); |
| (...skipping 1693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2075 DCHECK(shared->is_compiled()); | 1894 DCHECK(shared->is_compiled()); |
| 2076 function->set_literals(cached.literals); | 1895 function->set_literals(cached.literals); |
| 2077 } else if (shared->is_compiled()) { | 1896 } else if (shared->is_compiled()) { |
| 2078 // TODO(mvstanton): pass pretenure flag to EnsureLiterals. | 1897 // TODO(mvstanton): pass pretenure flag to EnsureLiterals. |
| 2079 JSFunction::EnsureLiterals(function); | 1898 JSFunction::EnsureLiterals(function); |
| 2080 } | 1899 } |
| 2081 } | 1900 } |
| 2082 | 1901 |
| 2083 } // namespace internal | 1902 } // namespace internal |
| 2084 } // namespace v8 | 1903 } // namespace v8 |
| OLD | NEW |