blob: bbe7f2fc9cd0579896854834261100e34e8d12c1 [file] [log] [blame]
Steve Block6ded16b2010-05-10 14:33:55 +01001// Copyright 2010 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
Ben Murdochf87a2032010-10-22 12:50:53 +010030#include "compiler.h"
31
Steve Blocka7e24c12009-10-30 11:49:00 +000032#include "bootstrapper.h"
33#include "codegen-inl.h"
34#include "compilation-cache.h"
Steve Block6ded16b2010-05-10 14:33:55 +010035#include "data-flow.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036#include "debug.h"
Leon Clarked91b9f72010-01-27 17:25:45 +000037#include "full-codegen.h"
Ben Murdochb8e0da22011-05-16 14:20:40 +010038#include "gdb-jit.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010039#include "hydrogen.h"
40#include "lithium-allocator.h"
Steve Block6ded16b2010-05-10 14:33:55 +010041#include "liveedit.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000042#include "oprofile-agent.h"
Ben Murdochf87a2032010-10-22 12:50:53 +010043#include "parser.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000044#include "rewriter.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010045#include "runtime-profiler.h"
Ben Murdoch3bec4d22010-07-22 14:51:16 +010046#include "scopeinfo.h"
Ben Murdochf87a2032010-10-22 12:50:53 +010047#include "scopes.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010048#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000049
50namespace v8 {
51namespace internal {
52
Ben Murdochf87a2032010-10-22 12:50:53 +010053
54CompilationInfo::CompilationInfo(Handle<Script> script)
55 : flags_(0),
56 function_(NULL),
57 scope_(NULL),
58 script_(script),
59 extension_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +010060 pre_parse_data_(NULL),
61 supports_deoptimization_(false),
62 osr_ast_id_(AstNode::kNoNumber) {
63 Initialize(NONOPT);
Ben Murdochf87a2032010-10-22 12:50:53 +010064}
65
66
67CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info)
68 : flags_(IsLazy::encode(true)),
69 function_(NULL),
70 scope_(NULL),
71 shared_info_(shared_info),
72 script_(Handle<Script>(Script::cast(shared_info->script()))),
73 extension_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +010074 pre_parse_data_(NULL),
75 supports_deoptimization_(false),
76 osr_ast_id_(AstNode::kNoNumber) {
77 Initialize(BASE);
Ben Murdochf87a2032010-10-22 12:50:53 +010078}
79
80
81CompilationInfo::CompilationInfo(Handle<JSFunction> closure)
82 : flags_(IsLazy::encode(true)),
83 function_(NULL),
84 scope_(NULL),
85 closure_(closure),
86 shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
87 script_(Handle<Script>(Script::cast(shared_info_->script()))),
88 extension_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +010089 pre_parse_data_(NULL),
90 supports_deoptimization_(false),
91 osr_ast_id_(AstNode::kNoNumber) {
92 Initialize(BASE);
Ben Murdochf87a2032010-10-22 12:50:53 +010093}
94
95
Ben Murdochb8e0da22011-05-16 14:20:40 +010096void CompilationInfo::DisableOptimization() {
97 if (FLAG_optimize_closures) {
98 // If we allow closures optimizations and it's an optimizable closure
99 // mark it correspondingly.
100 bool is_closure = closure_.is_null() && !scope_->HasTrivialOuterContext();
101 if (is_closure) {
102 bool is_optimizable_closure =
103 !scope_->outer_scope_calls_eval() && !scope_->inside_with();
104 if (is_optimizable_closure) {
105 SetMode(BASE);
106 return;
107 }
108 }
109 }
110
111 SetMode(NONOPT);
112}
113
114
Ben Murdochb0fe1622011-05-05 13:52:32 +0100115// Determine whether to use the full compiler for all code. If the flag
116// --always-full-compiler is specified this is the case. For the virtual frame
117// based compiler the full compiler is also used if a debugger is connected, as
118// the code from the full compiler supports mode precise break points. For the
119// crankshaft adaptive compiler debugging the optimized code is not possible at
120// all. However crankshaft support recompilation of functions, so in this case
121// the full compiler need not be be used if a debugger is attached, but only if
122// break points has actually been set.
Leon Clarkef7060e22010-06-03 12:02:55 +0100123static bool AlwaysFullCompiler() {
124#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdochb0fe1622011-05-05 13:52:32 +0100125 if (V8::UseCrankshaft()) {
126 return FLAG_always_full_compiler || Debug::has_break_points();
127 } else {
128 return FLAG_always_full_compiler || Debugger::IsDebuggerActive();
129 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100130#else
131 return FLAG_always_full_compiler;
132#endif
133}
134
Steve Block3ce2e202009-11-05 08:53:23 +0000135
Ben Murdochb0fe1622011-05-05 13:52:32 +0100136static void FinishOptimization(Handle<JSFunction> function, int64_t start) {
137 int opt_count = function->shared()->opt_count();
138 function->shared()->set_opt_count(opt_count + 1);
139 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
140 if (FLAG_trace_opt) {
141 PrintF("[optimizing: ");
142 function->PrintName();
143 PrintF(" / %" V8PRIxPTR, reinterpret_cast<intptr_t>(*function));
144 PrintF(" - took %0.3f ms]\n", ms);
145 }
146 if (FLAG_trace_opt_stats) {
147 static double compilation_time = 0.0;
148 static int compiled_functions = 0;
149 static int code_size = 0;
150
151 compilation_time += ms;
152 compiled_functions++;
153 code_size += function->shared()->SourceSize();
154 PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
155 compiled_functions,
156 code_size,
157 compilation_time);
158 }
159}
160
161
162static void AbortAndDisable(CompilationInfo* info) {
163 // Disable optimization for the shared function info and mark the
164 // code as non-optimizable. The marker on the shared function info
165 // is there because we flush non-optimized code thereby loosing the
166 // non-optimizable information for the code. When the code is
167 // regenerated and set on the shared function info it is marked as
168 // non-optimizable if optimization is disabled for the shared
169 // function info.
170 Handle<SharedFunctionInfo> shared = info->shared_info();
171 shared->set_optimization_disabled(true);
172 Handle<Code> code = Handle<Code>(shared->code());
173 ASSERT(code->kind() == Code::FUNCTION);
174 code->set_optimizable(false);
175 info->SetCode(code);
176 if (FLAG_trace_opt) {
177 PrintF("[disabled optimization for: ");
178 info->closure()->PrintName();
179 PrintF(" / %" V8PRIxPTR "]\n",
180 reinterpret_cast<intptr_t>(*info->closure()));
181 }
182}
183
184
185static bool MakeCrankshaftCode(CompilationInfo* info) {
186 // Test if we can optimize this function when asked to. We can only
187 // do this after the scopes are computed.
188 if (!info->AllowOptimize()) info->DisableOptimization();
189
190 // In case we are not optimizing simply return the code from
191 // the full code generator.
192 if (!info->IsOptimizing()) {
193 return FullCodeGenerator::MakeCode(info);
194 }
195
196 // We should never arrive here if there is not code object on the
197 // shared function object.
198 Handle<Code> code(info->shared_info()->code());
199 ASSERT(code->kind() == Code::FUNCTION);
200
201 // Fall back to using the full code generator if it's not possible
202 // to use the Hydrogen-based optimizing compiler. We already have
203 // generated code for this from the shared function object.
204 if (AlwaysFullCompiler() || !FLAG_use_hydrogen) {
205 info->SetCode(code);
206 return true;
207 }
208
209 // Limit the number of times we re-compile a functions with
210 // the optimizing compiler.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100211 const int kMaxOptCount =
212 FLAG_deopt_every_n_times == 0 ? Compiler::kDefaultMaxOptCount : 1000;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100213 if (info->shared_info()->opt_count() > kMaxOptCount) {
214 AbortAndDisable(info);
215 // True indicates the compilation pipeline is still going, not
216 // necessarily that we optimized the code.
217 return true;
218 }
219
220 // Due to an encoding limit on LUnallocated operands in the Lithium
221 // language, we cannot optimize functions with too many formal parameters
222 // or perform on-stack replacement for function with too many
223 // stack-allocated local variables.
224 //
225 // The encoding is as a signed value, with parameters using the negative
226 // indices and locals the non-negative ones.
227 const int limit = LUnallocated::kMaxFixedIndices / 2;
228 Scope* scope = info->scope();
229 if (scope->num_parameters() > limit || scope->num_stack_slots() > limit) {
230 AbortAndDisable(info);
231 // True indicates the compilation pipeline is still going, not
232 // necessarily that we optimized the code.
233 return true;
234 }
235
236 // Take --hydrogen-filter into account.
237 Vector<const char> filter = CStrVector(FLAG_hydrogen_filter);
238 Handle<String> name = info->function()->debug_name();
239 bool match = filter.is_empty() || name->IsEqualTo(filter);
240 if (!match) {
241 info->SetCode(code);
242 return true;
243 }
244
245 // Recompile the unoptimized version of the code if the current version
246 // doesn't have deoptimization support. Alternatively, we may decide to
247 // run the full code generator to get a baseline for the compile-time
248 // performance of the hydrogen-based compiler.
249 int64_t start = OS::Ticks();
250 bool should_recompile = !info->shared_info()->has_deoptimization_support();
251 if (should_recompile || FLAG_time_hydrogen) {
252 HPhase phase(HPhase::kFullCodeGen);
253 CompilationInfo unoptimized(info->shared_info());
254 // Note that we use the same AST that we will use for generating the
255 // optimized code.
256 unoptimized.SetFunction(info->function());
257 unoptimized.SetScope(info->scope());
258 if (should_recompile) unoptimized.EnableDeoptimizationSupport();
259 bool succeeded = FullCodeGenerator::MakeCode(&unoptimized);
260 if (should_recompile) {
261 if (!succeeded) return false;
262 Handle<SharedFunctionInfo> shared = info->shared_info();
263 shared->EnableDeoptimizationSupport(*unoptimized.code());
264 // The existing unoptimized code was replaced with the new one.
265 Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG,
266 Handle<String>(shared->DebugName()),
267 shared->start_position(),
268 &unoptimized);
269 }
270 }
271
272 // Check that the unoptimized, shared code is ready for
273 // optimizations. When using the always_opt flag we disregard the
274 // optimizable marker in the code object and optimize anyway. This
275 // is safe as long as the unoptimized code has deoptimization
276 // support.
277 ASSERT(FLAG_always_opt || info->shared_info()->code()->optimizable());
278 ASSERT(info->shared_info()->has_deoptimization_support());
279
280 if (FLAG_trace_hydrogen) {
281 PrintF("-----------------------------------------------------------\n");
282 PrintF("Compiling method %s using hydrogen\n", *name->ToCString());
283 HTracer::Instance()->TraceCompilation(info->function());
284 }
285
Ben Murdochb8e0da22011-05-16 14:20:40 +0100286 TypeFeedbackOracle oracle(
287 Handle<Code>(info->shared_info()->code()),
288 Handle<Context>(info->closure()->context()->global_context()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100289 HGraphBuilder builder(&oracle);
290 HPhase phase(HPhase::kTotal);
291 HGraph* graph = builder.CreateGraph(info);
292 if (graph != NULL && FLAG_build_lithium) {
293 Handle<Code> code = graph->Compile();
294 if (!code.is_null()) {
295 info->SetCode(code);
296 FinishOptimization(info->closure(), start);
297 return true;
298 }
299 }
300
301 // Compilation with the Hydrogen compiler failed. Keep using the
302 // shared code but mark it as unoptimizable.
303 AbortAndDisable(info);
304 // True indicates the compilation pipeline is still going, not necessarily
305 // that we optimized the code.
306 return true;
307}
308
309
Ben Murdochf87a2032010-10-22 12:50:53 +0100310static bool MakeCode(CompilationInfo* info) {
311 // Precondition: code has been parsed. Postcondition: the code field in
312 // the compilation info is set if compilation succeeded.
313 ASSERT(info->function() != NULL);
314
Ben Murdochb0fe1622011-05-05 13:52:32 +0100315 if (Rewriter::Rewrite(info) && Scope::Analyze(info)) {
316 if (V8::UseCrankshaft()) return MakeCrankshaftCode(info);
317
Ben Murdochf87a2032010-10-22 12:50:53 +0100318 // Generate code and return it. Code generator selection is governed by
319 // which backends are enabled and whether the function is considered
320 // run-once code or not.
321 //
322 // --full-compiler enables the dedicated backend for code we expect to
323 // be run once
324 //
325 // The normal choice of backend can be overridden with the flags
326 // --always-full-compiler.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100327 if (Rewriter::Analyze(info)) {
328 Handle<SharedFunctionInfo> shared = info->shared_info();
329 bool is_run_once = (shared.is_null())
330 ? info->scope()->is_global_scope()
331 : (shared->is_toplevel() || shared->try_full_codegen());
332 bool can_use_full =
333 FLAG_full_compiler && !info->function()->contains_loops();
334 if (AlwaysFullCompiler() || (is_run_once && can_use_full)) {
335 return FullCodeGenerator::MakeCode(info);
336 } else {
337 return AssignedVariablesAnalyzer::Analyze(info) &&
338 CodeGenerator::MakeCode(info);
339 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100340 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000341 }
342
Ben Murdochf87a2032010-10-22 12:50:53 +0100343 return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000344}
345
346
Steve Block6ded16b2010-05-10 14:33:55 +0100347#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdochf87a2032010-10-22 12:50:53 +0100348bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) {
349 // Precondition: code has been parsed. Postcondition: the code field in
350 // the compilation info is set if compilation succeeded.
351 bool succeeded = MakeCode(info);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100352 if (!info->shared_info().is_null()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100353 Handle<SerializedScopeInfo> scope_info =
354 SerializedScopeInfo::Create(info->scope());
355 info->shared_info()->set_scope_info(*scope_info);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100356 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100357 return succeeded;
Steve Block6ded16b2010-05-10 14:33:55 +0100358}
359#endif
360
361
Ben Murdochf87a2032010-10-22 12:50:53 +0100362static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000363 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
364
365 PostponeInterruptsScope postpone;
366
367 ASSERT(!i::Top::global_context().is_null());
Ben Murdochf87a2032010-10-22 12:50:53 +0100368 Handle<Script> script = info->script();
Steve Blocka7e24c12009-10-30 11:49:00 +0000369 script->set_context_data((*i::Top::global_context())->data());
370
Leon Clarke4515c472010-02-03 11:58:03 +0000371#ifdef ENABLE_DEBUGGER_SUPPORT
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800372 if (info->is_eval()) {
373 Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL;
Ben Murdochf87a2032010-10-22 12:50:53 +0100374 script->set_compilation_type(Smi::FromInt(compilation_type));
Steve Blocka7e24c12009-10-30 11:49:00 +0000375 // For eval scripts add information on the function from which eval was
376 // called.
Ben Murdochf87a2032010-10-22 12:50:53 +0100377 if (info->is_eval()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000378 StackTraceFrameIterator it;
379 if (!it.done()) {
380 script->set_eval_from_shared(
381 JSFunction::cast(it.frame()->function())->shared());
382 int offset = static_cast<int>(
383 it.frame()->pc() - it.frame()->code()->instruction_start());
384 script->set_eval_from_instructions_offset(Smi::FromInt(offset));
385 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000386 }
387 }
388
389 // Notify debugger
390 Debugger::OnBeforeCompile(script);
391#endif
392
393 // Only allow non-global compiles for eval.
Ben Murdochf87a2032010-10-22 12:50:53 +0100394 ASSERT(info->is_eval() || info->is_global());
Steve Blocka7e24c12009-10-30 11:49:00 +0000395
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800396 if (!ParserApi::Parse(info)) return Handle<SharedFunctionInfo>::null();
Steve Blocka7e24c12009-10-30 11:49:00 +0000397
Steve Blocka7e24c12009-10-30 11:49:00 +0000398 // Measure how long it takes to do the compilation; only take the
399 // rest of the function into account to avoid overlap with the
400 // parsing statistics.
Ben Murdochf87a2032010-10-22 12:50:53 +0100401 HistogramTimer* rate = info->is_eval()
Steve Blocka7e24c12009-10-30 11:49:00 +0000402 ? &Counters::compile_eval
403 : &Counters::compile;
404 HistogramTimerScope timer(rate);
405
406 // Compile the code.
Ben Murdochf87a2032010-10-22 12:50:53 +0100407 FunctionLiteral* lit = info->function();
408 LiveEditFunctionTracker live_edit_tracker(lit);
409 if (!MakeCode(info)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000410 Top::StackOverflow();
Steve Block6ded16b2010-05-10 14:33:55 +0100411 return Handle<SharedFunctionInfo>::null();
Steve Blocka7e24c12009-10-30 11:49:00 +0000412 }
413
Ben Murdochf87a2032010-10-22 12:50:53 +0100414 ASSERT(!info->code().is_null());
Steve Block6ded16b2010-05-10 14:33:55 +0100415 if (script->name()->IsString()) {
416 PROFILE(CodeCreateEvent(
Ben Murdochf87a2032010-10-22 12:50:53 +0100417 info->is_eval()
418 ? Logger::EVAL_TAG
419 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
420 *info->code(),
421 String::cast(script->name())));
Steve Block6ded16b2010-05-10 14:33:55 +0100422 OPROFILE(CreateNativeCodeRegion(String::cast(script->name()),
Ben Murdochf87a2032010-10-22 12:50:53 +0100423 info->code()->instruction_start(),
424 info->code()->instruction_size()));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100425 GDBJIT(AddCode(Handle<String>(String::cast(script->name())),
426 script,
427 info->code()));
Steve Block6ded16b2010-05-10 14:33:55 +0100428 } else {
429 PROFILE(CodeCreateEvent(
Ben Murdochf87a2032010-10-22 12:50:53 +0100430 info->is_eval()
431 ? Logger::EVAL_TAG
432 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
433 *info->code(),
434 ""));
435 OPROFILE(CreateNativeCodeRegion(info->is_eval() ? "Eval" : "Script",
436 info->code()->instruction_start(),
437 info->code()->instruction_size()));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100438 GDBJIT(AddCode(Handle<String>(), script, info->code()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000439 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000440
441 // Allocate function.
Steve Block6ded16b2010-05-10 14:33:55 +0100442 Handle<SharedFunctionInfo> result =
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100443 Factory::NewSharedFunctionInfo(
444 lit->name(),
445 lit->materialized_literal_count(),
Ben Murdochf87a2032010-10-22 12:50:53 +0100446 info->code(),
447 SerializedScopeInfo::Create(info->scope()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000448
449 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
Steve Block6ded16b2010-05-10 14:33:55 +0100450 Compiler::SetFunctionInfo(result, lit, true, script);
Steve Blocka7e24c12009-10-30 11:49:00 +0000451
452 // Hint to the runtime system used when allocating space for initial
453 // property space by setting the expected number of properties for
454 // the instances of the function.
Steve Block6ded16b2010-05-10 14:33:55 +0100455 SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count());
Steve Blocka7e24c12009-10-30 11:49:00 +0000456
457#ifdef ENABLE_DEBUGGER_SUPPORT
458 // Notify debugger
Steve Block6ded16b2010-05-10 14:33:55 +0100459 Debugger::OnAfterCompile(script, Debugger::NO_AFTER_COMPILE_FLAGS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000460#endif
461
Steve Block6ded16b2010-05-10 14:33:55 +0100462 live_edit_tracker.RecordFunctionInfo(result, lit);
463
464 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000465}
466
467
Steve Block6ded16b2010-05-10 14:33:55 +0100468Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
469 Handle<Object> script_name,
470 int line_offset,
471 int column_offset,
472 v8::Extension* extension,
473 ScriptDataImpl* input_pre_data,
474 Handle<Object> script_data,
475 NativesFlag natives) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000476 int source_length = source->length();
477 Counters::total_load_size.Increment(source_length);
478 Counters::total_compile_size.Increment(source_length);
479
480 // The VM is in the COMPILER state until exiting this function.
481 VMState state(COMPILER);
482
483 // Do a lookup in the compilation cache but not for extensions.
Steve Block6ded16b2010-05-10 14:33:55 +0100484 Handle<SharedFunctionInfo> result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000485 if (extension == NULL) {
486 result = CompilationCache::LookupScript(source,
487 script_name,
488 line_offset,
489 column_offset);
490 }
491
492 if (result.is_null()) {
Steve Block59151502010-09-22 15:07:15 +0100493 // No cache entry found. Do pre-parsing, if it makes sense, and compile
494 // the script.
495 // Building preparse data that is only used immediately after is only a
496 // saving if we might skip building the AST for lazily compiled functions.
497 // I.e., preparse data isn't relevant when the lazy flag is off, and
498 // for small sources, odds are that there aren't many functions
499 // that would be compiled lazily anyway, so we skip the preparse step
500 // in that case too.
Steve Blocka7e24c12009-10-30 11:49:00 +0000501 ScriptDataImpl* pre_data = input_pre_data;
Steve Block59151502010-09-22 15:07:15 +0100502 if (pre_data == NULL
Steve Block59151502010-09-22 15:07:15 +0100503 && source_length >= FLAG_min_preparse_length) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100504 if (source->IsExternalTwoByteString()) {
505 ExternalTwoByteStringUC16CharacterStream stream(
506 Handle<ExternalTwoByteString>::cast(source), 0, source->length());
507 pre_data = ParserApi::PartialPreParse(&stream, extension);
508 } else {
509 GenericStringUC16CharacterStream stream(source, 0, source->length());
510 pre_data = ParserApi::PartialPreParse(&stream, extension);
511 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000512 }
513
514 // Create a script object describing the script to be compiled.
515 Handle<Script> script = Factory::NewScript(source);
Andrei Popescu31002712010-02-23 13:46:05 +0000516 if (natives == NATIVES_CODE) {
517 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
518 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000519 if (!script_name.is_null()) {
520 script->set_name(*script_name);
521 script->set_line_offset(Smi::FromInt(line_offset));
522 script->set_column_offset(Smi::FromInt(column_offset));
523 }
524
Andrei Popescu402d9372010-02-26 13:31:12 +0000525 script->set_data(script_data.is_null() ? Heap::undefined_value()
526 : *script_data);
527
Steve Blocka7e24c12009-10-30 11:49:00 +0000528 // Compile the function and add it to the cache.
Ben Murdochf87a2032010-10-22 12:50:53 +0100529 CompilationInfo info(script);
530 info.MarkAsGlobal();
531 info.SetExtension(extension);
532 info.SetPreParseData(pre_data);
533 result = MakeFunctionInfo(&info);
Steve Blocka7e24c12009-10-30 11:49:00 +0000534 if (extension == NULL && !result.is_null()) {
535 CompilationCache::PutScript(source, result);
536 }
537
538 // Get rid of the pre-parsing data (if necessary).
539 if (input_pre_data == NULL && pre_data != NULL) {
540 delete pre_data;
541 }
542 }
543
544 if (result.is_null()) Top::ReportPendingMessages();
545 return result;
546}
547
548
Steve Block6ded16b2010-05-10 14:33:55 +0100549Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
550 Handle<Context> context,
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800551 bool is_global) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000552 int source_length = source->length();
553 Counters::total_eval_size.Increment(source_length);
554 Counters::total_compile_size.Increment(source_length);
555
556 // The VM is in the COMPILER state until exiting this function.
557 VMState state(COMPILER);
558
Ben Murdochf87a2032010-10-22 12:50:53 +0100559 // Do a lookup in the compilation cache; if the entry is not there, invoke
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800560 // the compiler and add the result to the cache.
Steve Block6ded16b2010-05-10 14:33:55 +0100561 Handle<SharedFunctionInfo> result;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800562 result = CompilationCache::LookupEval(source, context, is_global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000563
564 if (result.is_null()) {
565 // Create a script object describing the script to be compiled.
566 Handle<Script> script = Factory::NewScript(source);
Ben Murdochf87a2032010-10-22 12:50:53 +0100567 CompilationInfo info(script);
568 info.MarkAsEval();
569 if (is_global) info.MarkAsGlobal();
Ben Murdochf87a2032010-10-22 12:50:53 +0100570 info.SetCallingContext(context);
571 result = MakeFunctionInfo(&info);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800572 if (!result.is_null()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 CompilationCache::PutEval(source, context, is_global, result);
574 }
575 }
576
577 return result;
578}
579
580
Leon Clarke4515c472010-02-03 11:58:03 +0000581bool Compiler::CompileLazy(CompilationInfo* info) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000582 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
583
584 // The VM is in the COMPILER state until exiting this function.
585 VMState state(COMPILER);
586
587 PostponeInterruptsScope postpone;
588
Leon Clarke4515c472010-02-03 11:58:03 +0000589 Handle<SharedFunctionInfo> shared = info->shared_info();
Ben Murdochf87a2032010-10-22 12:50:53 +0100590 int compiled_size = shared->end_position() - shared->start_position();
591 Counters::total_compile_size.Increment(compiled_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000592
Ben Murdochf87a2032010-10-22 12:50:53 +0100593 // Generate the AST for the lazily compiled function.
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800594 if (ParserApi::Parse(info)) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100595 // Measure how long it takes to do the lazy compilation; only take the
596 // rest of the function into account to avoid overlap with the lazy
597 // parsing statistics.
598 HistogramTimerScope timer(&Counters::compile_lazy);
Steve Blocka7e24c12009-10-30 11:49:00 +0000599
Ben Murdochf87a2032010-10-22 12:50:53 +0100600 // Compile the code.
601 if (!MakeCode(info)) {
602 Top::StackOverflow();
603 } else {
604 ASSERT(!info->code().is_null());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100605 Handle<Code> code = info->code();
606 Handle<JSFunction> function = info->closure();
Ben Murdochf87a2032010-10-22 12:50:53 +0100607 RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG,
608 Handle<String>(shared->DebugName()),
609 shared->start_position(),
610 info);
Steve Blocka7e24c12009-10-30 11:49:00 +0000611
Ben Murdochb0fe1622011-05-05 13:52:32 +0100612 if (info->IsOptimizing()) {
613 function->ReplaceCode(*code);
614 } else {
615 // Update the shared function info with the compiled code and the
616 // scope info. Please note, that the order of the shared function
617 // info initialization is important since set_scope_info might
618 // trigger a GC, causing the ASSERT below to be invalid if the code
619 // was flushed. By settting the code object last we avoid this.
620 Handle<SerializedScopeInfo> scope_info =
621 SerializedScopeInfo::Create(info->scope());
622 shared->set_scope_info(*scope_info);
623 shared->set_code(*code);
624 if (!function.is_null()) {
625 function->ReplaceCode(*code);
626 ASSERT(!function->IsOptimized());
627 }
628
629 // Set the expected number of properties for instances.
630 FunctionLiteral* lit = info->function();
631 int expected = lit->expected_property_count();
632 SetExpectedNofPropertiesFromEstimate(shared, expected);
633
634 // Set the optimization hints after performing lazy compilation, as
635 // these are not set when the function is set up as a lazily
636 // compiled function.
637 shared->SetThisPropertyAssignmentsInfo(
638 lit->has_only_simple_this_property_assignments(),
639 *lit->this_property_assignments());
640
641 // Check the function has compiled code.
642 ASSERT(shared->is_compiled());
643 shared->set_code_age(0);
644
645 if (V8::UseCrankshaft() && info->AllowOptimize()) {
646 // If we're asked to always optimize, we compile the optimized
647 // version of the function right away - unless the debugger is
648 // active as it makes no sense to compile optimized code then.
649 if (FLAG_always_opt && !Debug::has_break_points()) {
650 CompilationInfo optimized(function);
651 optimized.SetOptimizing(AstNode::kNoNumber);
652 return CompileLazy(&optimized);
653 } else if (CompilationCache::ShouldOptimizeEagerly(function)) {
654 RuntimeProfiler::OptimizeSoon(*function);
655 }
656 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100657 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000658
Ben Murdochf87a2032010-10-22 12:50:53 +0100659 return true;
660 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000661 }
662
Ben Murdochf87a2032010-10-22 12:50:53 +0100663 ASSERT(info->code().is_null());
664 return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000665}
666
667
Steve Block6ded16b2010-05-10 14:33:55 +0100668Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
Ben Murdochf87a2032010-10-22 12:50:53 +0100669 Handle<Script> script) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100670 // Precondition: code has been parsed and scopes have been analyzed.
671 CompilationInfo info(script);
672 info.SetFunction(literal);
673 info.SetScope(literal->scope());
674
675 LiveEditFunctionTracker live_edit_tracker(literal);
676 // Determine if the function can be lazily compiled. This is necessary to
677 // allow some of our builtin JS files to be lazily compiled. These
678 // builtins cannot be handled lazily by the parser, since we have to know
679 // if a function uses the special natives syntax, which is something the
680 // parser records.
Andrei Popescu402d9372010-02-26 13:31:12 +0000681 bool allow_lazy = literal->AllowsLazyCompilation() &&
682 !LiveEditFunctionTracker::IsActive();
Steve Blockd0582a62009-12-15 09:54:21 +0000683
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100684 Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty());
685
Steve Blockd0582a62009-12-15 09:54:21 +0000686 // Generate code
Steve Blockd0582a62009-12-15 09:54:21 +0000687 if (FLAG_lazy && allow_lazy) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100688 Handle<Code> code(Builtins::builtin(Builtins::LazyCompile));
689 info.SetCode(code);
Steve Blockd0582a62009-12-15 09:54:21 +0000690 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100691 if (V8::UseCrankshaft()) {
692 if (!MakeCrankshaftCode(&info)) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100693 return Handle<SharedFunctionInfo>::null();
694 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100695 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100696 // The bodies of function literals have not yet been visited by the
697 // AST optimizer/analyzer.
698 if (!Rewriter::Analyze(&info)) return Handle<SharedFunctionInfo>::null();
699
700 bool is_run_once = literal->try_full_codegen();
701 bool can_use_full = FLAG_full_compiler && !literal->contains_loops();
702
703 if (AlwaysFullCompiler() || (is_run_once && can_use_full)) {
704 if (!FullCodeGenerator::MakeCode(&info)) {
705 return Handle<SharedFunctionInfo>::null();
706 }
707 } else {
708 // We fall back to the classic V8 code generator.
709 if (!AssignedVariablesAnalyzer::Analyze(&info) ||
710 !CodeGenerator::MakeCode(&info)) {
711 return Handle<SharedFunctionInfo>::null();
712 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100713 }
Steve Blockd0582a62009-12-15 09:54:21 +0000714 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100715 ASSERT(!info.code().is_null());
Steve Blockd0582a62009-12-15 09:54:21 +0000716
717 // Function compilation complete.
Steve Block6ded16b2010-05-10 14:33:55 +0100718 RecordFunctionCompilation(Logger::FUNCTION_TAG,
Ben Murdochf87a2032010-10-22 12:50:53 +0100719 literal->debug_name(),
Steve Block6ded16b2010-05-10 14:33:55 +0100720 literal->start_position(),
Ben Murdochf87a2032010-10-22 12:50:53 +0100721 &info);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100722 scope_info = SerializedScopeInfo::Create(info.scope());
Steve Blockd0582a62009-12-15 09:54:21 +0000723 }
724
Steve Block6ded16b2010-05-10 14:33:55 +0100725 // Create a shared function info object.
726 Handle<SharedFunctionInfo> result =
727 Factory::NewSharedFunctionInfo(literal->name(),
728 literal->materialized_literal_count(),
Ben Murdochf87a2032010-10-22 12:50:53 +0100729 info.code(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100730 scope_info);
Steve Block6ded16b2010-05-10 14:33:55 +0100731 SetFunctionInfo(result, literal, false, script);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100732 result->set_allows_lazy_compilation(allow_lazy);
Steve Blockd0582a62009-12-15 09:54:21 +0000733
734 // Set the expected number of properties for instances and return
735 // the resulting function.
Steve Block6ded16b2010-05-10 14:33:55 +0100736 SetExpectedNofPropertiesFromEstimate(result,
Steve Blockd0582a62009-12-15 09:54:21 +0000737 literal->expected_property_count());
Steve Block6ded16b2010-05-10 14:33:55 +0100738 live_edit_tracker.RecordFunctionInfo(result, literal);
739 return result;
Steve Blockd0582a62009-12-15 09:54:21 +0000740}
741
742
743// Sets the function info on a function.
744// The start_position points to the first '(' character after the function name
745// in the full script source. When counting characters in the script source the
746// the first character is number 0 (not 1).
Steve Block6ded16b2010-05-10 14:33:55 +0100747void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
Steve Blockd0582a62009-12-15 09:54:21 +0000748 FunctionLiteral* lit,
749 bool is_toplevel,
750 Handle<Script> script) {
Steve Block6ded16b2010-05-10 14:33:55 +0100751 function_info->set_length(lit->num_parameters());
752 function_info->set_formal_parameter_count(lit->num_parameters());
753 function_info->set_script(*script);
754 function_info->set_function_token_position(lit->function_token_position());
755 function_info->set_start_position(lit->start_position());
756 function_info->set_end_position(lit->end_position());
757 function_info->set_is_expression(lit->is_expression());
758 function_info->set_is_toplevel(is_toplevel);
759 function_info->set_inferred_name(*lit->inferred_name());
760 function_info->SetThisPropertyAssignmentsInfo(
Steve Blockd0582a62009-12-15 09:54:21 +0000761 lit->has_only_simple_this_property_assignments(),
762 *lit->this_property_assignments());
Steve Block6ded16b2010-05-10 14:33:55 +0100763 function_info->set_try_full_codegen(lit->try_full_codegen());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100764 function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
Steve Blockd0582a62009-12-15 09:54:21 +0000765}
766
767
Steve Block6ded16b2010-05-10 14:33:55 +0100768void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
769 Handle<String> name,
Steve Block6ded16b2010-05-10 14:33:55 +0100770 int start_position,
Ben Murdochf87a2032010-10-22 12:50:53 +0100771 CompilationInfo* info) {
772 // Log the code generation. If source information is available include
773 // script name and line number. Check explicitly whether logging is
774 // enabled as finding the line number is not free.
775 if (Logger::is_logging() ||
776 OProfileAgent::is_enabled() ||
777 CpuProfiler::is_profiling()) {
778 Handle<Script> script = info->script();
779 Handle<Code> code = info->code();
Andrei Popescu31002712010-02-23 13:46:05 +0000780 if (script->name()->IsString()) {
781 int line_num = GetScriptLineNumber(script, start_position) + 1;
Steve Block6ded16b2010-05-10 14:33:55 +0100782 USE(line_num);
783 PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
Ben Murdochf87a2032010-10-22 12:50:53 +0100784 *code,
785 *name,
786 String::cast(script->name()),
787 line_num));
788 OPROFILE(CreateNativeCodeRegion(*name,
Steve Block6ded16b2010-05-10 14:33:55 +0100789 String::cast(script->name()),
790 line_num,
791 code->instruction_start(),
792 code->instruction_size()));
Andrei Popescu31002712010-02-23 13:46:05 +0000793 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100794 PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
Ben Murdochf87a2032010-10-22 12:50:53 +0100795 *code,
796 *name));
797 OPROFILE(CreateNativeCodeRegion(*name,
Steve Block6ded16b2010-05-10 14:33:55 +0100798 code->instruction_start(),
799 code->instruction_size()));
Andrei Popescu31002712010-02-23 13:46:05 +0000800 }
801 }
Ben Murdochb8e0da22011-05-16 14:20:40 +0100802
803 GDBJIT(AddCode(name,
804 Handle<Script>(info->script()),
805 Handle<Code>(info->code())));
Andrei Popescu31002712010-02-23 13:46:05 +0000806}
Andrei Popescu31002712010-02-23 13:46:05 +0000807
Steve Blocka7e24c12009-10-30 11:49:00 +0000808} } // namespace v8::internal