blob: 667432f22fdba431731faac445fbcf16bf1c02e4 [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"
Steve Block1e0659c2011-05-24 12:43:12 +010040#include "lithium.h"
Steve Block6ded16b2010-05-10 14:33:55 +010041#include "liveedit.h"
Ben Murdochf87a2032010-10-22 12:50:53 +010042#include "parser.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000043#include "rewriter.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010044#include "runtime-profiler.h"
Ben Murdoch3bec4d22010-07-22 14:51:16 +010045#include "scopeinfo.h"
Ben Murdochf87a2032010-10-22 12:50:53 +010046#include "scopes.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010047#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000048
49namespace v8 {
50namespace internal {
51
Ben Murdochf87a2032010-10-22 12:50:53 +010052
53CompilationInfo::CompilationInfo(Handle<Script> script)
54 : flags_(0),
55 function_(NULL),
56 scope_(NULL),
57 script_(script),
58 extension_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +010059 pre_parse_data_(NULL),
60 supports_deoptimization_(false),
61 osr_ast_id_(AstNode::kNoNumber) {
62 Initialize(NONOPT);
Ben Murdochf87a2032010-10-22 12:50:53 +010063}
64
65
66CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info)
67 : flags_(IsLazy::encode(true)),
68 function_(NULL),
69 scope_(NULL),
70 shared_info_(shared_info),
71 script_(Handle<Script>(Script::cast(shared_info->script()))),
72 extension_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +010073 pre_parse_data_(NULL),
74 supports_deoptimization_(false),
75 osr_ast_id_(AstNode::kNoNumber) {
76 Initialize(BASE);
Ben Murdochf87a2032010-10-22 12:50:53 +010077}
78
79
80CompilationInfo::CompilationInfo(Handle<JSFunction> closure)
81 : flags_(IsLazy::encode(true)),
82 function_(NULL),
83 scope_(NULL),
84 closure_(closure),
85 shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
86 script_(Handle<Script>(Script::cast(shared_info_->script()))),
87 extension_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +010088 pre_parse_data_(NULL),
89 supports_deoptimization_(false),
90 osr_ast_id_(AstNode::kNoNumber) {
91 Initialize(BASE);
Ben Murdochf87a2032010-10-22 12:50:53 +010092}
93
94
Ben Murdochb8e0da22011-05-16 14:20:40 +010095void CompilationInfo::DisableOptimization() {
96 if (FLAG_optimize_closures) {
97 // If we allow closures optimizations and it's an optimizable closure
98 // mark it correspondingly.
99 bool is_closure = closure_.is_null() && !scope_->HasTrivialOuterContext();
100 if (is_closure) {
101 bool is_optimizable_closure =
102 !scope_->outer_scope_calls_eval() && !scope_->inside_with();
103 if (is_optimizable_closure) {
104 SetMode(BASE);
105 return;
106 }
107 }
108 }
109
110 SetMode(NONOPT);
111}
112
113
Ben Murdochb0fe1622011-05-05 13:52:32 +0100114// Determine whether to use the full compiler for all code. If the flag
115// --always-full-compiler is specified this is the case. For the virtual frame
116// based compiler the full compiler is also used if a debugger is connected, as
117// the code from the full compiler supports mode precise break points. For the
118// crankshaft adaptive compiler debugging the optimized code is not possible at
119// all. However crankshaft support recompilation of functions, so in this case
120// the full compiler need not be be used if a debugger is attached, but only if
121// break points has actually been set.
Leon Clarkef7060e22010-06-03 12:02:55 +0100122static bool AlwaysFullCompiler() {
123#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdochb0fe1622011-05-05 13:52:32 +0100124 if (V8::UseCrankshaft()) {
125 return FLAG_always_full_compiler || Debug::has_break_points();
126 } else {
127 return FLAG_always_full_compiler || Debugger::IsDebuggerActive();
128 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100129#else
130 return FLAG_always_full_compiler;
131#endif
132}
133
Steve Block3ce2e202009-11-05 08:53:23 +0000134
Ben Murdochb0fe1622011-05-05 13:52:32 +0100135static void FinishOptimization(Handle<JSFunction> function, int64_t start) {
136 int opt_count = function->shared()->opt_count();
137 function->shared()->set_opt_count(opt_count + 1);
138 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
139 if (FLAG_trace_opt) {
140 PrintF("[optimizing: ");
141 function->PrintName();
142 PrintF(" / %" V8PRIxPTR, reinterpret_cast<intptr_t>(*function));
143 PrintF(" - took %0.3f ms]\n", ms);
144 }
145 if (FLAG_trace_opt_stats) {
146 static double compilation_time = 0.0;
147 static int compiled_functions = 0;
148 static int code_size = 0;
149
150 compilation_time += ms;
151 compiled_functions++;
152 code_size += function->shared()->SourceSize();
153 PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
154 compiled_functions,
155 code_size,
156 compilation_time);
157 }
158}
159
160
161static void AbortAndDisable(CompilationInfo* info) {
162 // Disable optimization for the shared function info and mark the
163 // code as non-optimizable. The marker on the shared function info
164 // is there because we flush non-optimized code thereby loosing the
165 // non-optimizable information for the code. When the code is
166 // regenerated and set on the shared function info it is marked as
167 // non-optimizable if optimization is disabled for the shared
168 // function info.
169 Handle<SharedFunctionInfo> shared = info->shared_info();
170 shared->set_optimization_disabled(true);
171 Handle<Code> code = Handle<Code>(shared->code());
172 ASSERT(code->kind() == Code::FUNCTION);
173 code->set_optimizable(false);
174 info->SetCode(code);
175 if (FLAG_trace_opt) {
176 PrintF("[disabled optimization for: ");
177 info->closure()->PrintName();
178 PrintF(" / %" V8PRIxPTR "]\n",
179 reinterpret_cast<intptr_t>(*info->closure()));
180 }
181}
182
183
184static bool MakeCrankshaftCode(CompilationInfo* info) {
185 // Test if we can optimize this function when asked to. We can only
186 // do this after the scopes are computed.
187 if (!info->AllowOptimize()) info->DisableOptimization();
188
189 // In case we are not optimizing simply return the code from
190 // the full code generator.
191 if (!info->IsOptimizing()) {
192 return FullCodeGenerator::MakeCode(info);
193 }
194
195 // We should never arrive here if there is not code object on the
196 // shared function object.
197 Handle<Code> code(info->shared_info()->code());
198 ASSERT(code->kind() == Code::FUNCTION);
199
200 // Fall back to using the full code generator if it's not possible
201 // to use the Hydrogen-based optimizing compiler. We already have
202 // generated code for this from the shared function object.
203 if (AlwaysFullCompiler() || !FLAG_use_hydrogen) {
204 info->SetCode(code);
205 return true;
206 }
207
208 // Limit the number of times we re-compile a functions with
209 // the optimizing compiler.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100210 const int kMaxOptCount =
211 FLAG_deopt_every_n_times == 0 ? Compiler::kDefaultMaxOptCount : 1000;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100212 if (info->shared_info()->opt_count() > kMaxOptCount) {
213 AbortAndDisable(info);
214 // True indicates the compilation pipeline is still going, not
215 // necessarily that we optimized the code.
216 return true;
217 }
218
219 // Due to an encoding limit on LUnallocated operands in the Lithium
220 // language, we cannot optimize functions with too many formal parameters
221 // or perform on-stack replacement for function with too many
222 // stack-allocated local variables.
223 //
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100224 // The encoding is as a signed value, with parameters and receiver using
225 // the negative indices and locals the non-negative ones.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100226 const int limit = LUnallocated::kMaxFixedIndices / 2;
227 Scope* scope = info->scope();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100228 if ((scope->num_parameters() + 1) > limit ||
229 scope->num_stack_slots() > limit) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100230 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.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100265 Compiler::RecordFunctionCompilation(
266 Logger::LAZY_COMPILE_TAG, &unoptimized, shared);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100267 }
268 }
269
270 // Check that the unoptimized, shared code is ready for
271 // optimizations. When using the always_opt flag we disregard the
272 // optimizable marker in the code object and optimize anyway. This
273 // is safe as long as the unoptimized code has deoptimization
274 // support.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100275 ASSERT(FLAG_always_opt || code->optimizable());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100276 ASSERT(info->shared_info()->has_deoptimization_support());
277
278 if (FLAG_trace_hydrogen) {
279 PrintF("-----------------------------------------------------------\n");
280 PrintF("Compiling method %s using hydrogen\n", *name->ToCString());
281 HTracer::Instance()->TraceCompilation(info->function());
282 }
283
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100284 Handle<Context> global_context(info->closure()->context()->global_context());
285 TypeFeedbackOracle oracle(code, global_context);
286 HGraphBuilder builder(info, &oracle);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100287 HPhase phase(HPhase::kTotal);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100288 HGraph* graph = builder.CreateGraph();
Steve Block1e0659c2011-05-24 12:43:12 +0100289 if (Top::has_pending_exception()) {
290 info->SetCode(Handle<Code>::null());
291 return false;
292 }
293
Ben Murdochb0fe1622011-05-05 13:52:32 +0100294 if (graph != NULL && FLAG_build_lithium) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100295 Handle<Code> optimized_code = graph->Compile(info);
296 if (!optimized_code.is_null()) {
297 info->SetCode(optimized_code);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100298 FinishOptimization(info->closure(), start);
299 return true;
300 }
301 }
302
303 // Compilation with the Hydrogen compiler failed. Keep using the
304 // shared code but mark it as unoptimizable.
305 AbortAndDisable(info);
306 // True indicates the compilation pipeline is still going, not necessarily
307 // that we optimized the code.
308 return true;
309}
310
311
Ben Murdochf87a2032010-10-22 12:50:53 +0100312static bool MakeCode(CompilationInfo* info) {
313 // Precondition: code has been parsed. Postcondition: the code field in
314 // the compilation info is set if compilation succeeded.
315 ASSERT(info->function() != NULL);
316
Ben Murdochb0fe1622011-05-05 13:52:32 +0100317 if (Rewriter::Rewrite(info) && Scope::Analyze(info)) {
318 if (V8::UseCrankshaft()) return MakeCrankshaftCode(info);
319
Ben Murdochf87a2032010-10-22 12:50:53 +0100320 // Generate code and return it. Code generator selection is governed by
321 // which backends are enabled and whether the function is considered
322 // run-once code or not.
323 //
324 // --full-compiler enables the dedicated backend for code we expect to
325 // be run once
326 //
327 // The normal choice of backend can be overridden with the flags
328 // --always-full-compiler.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100329 if (Rewriter::Analyze(info)) {
330 Handle<SharedFunctionInfo> shared = info->shared_info();
331 bool is_run_once = (shared.is_null())
332 ? info->scope()->is_global_scope()
333 : (shared->is_toplevel() || shared->try_full_codegen());
334 bool can_use_full =
335 FLAG_full_compiler && !info->function()->contains_loops();
336 if (AlwaysFullCompiler() || (is_run_once && can_use_full)) {
337 return FullCodeGenerator::MakeCode(info);
338 } else {
339 return AssignedVariablesAnalyzer::Analyze(info) &&
340 CodeGenerator::MakeCode(info);
341 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100342 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000343 }
344
Ben Murdochf87a2032010-10-22 12:50:53 +0100345 return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000346}
347
348
Steve Block6ded16b2010-05-10 14:33:55 +0100349#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdochf87a2032010-10-22 12:50:53 +0100350bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) {
351 // Precondition: code has been parsed. Postcondition: the code field in
352 // the compilation info is set if compilation succeeded.
353 bool succeeded = MakeCode(info);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100354 if (!info->shared_info().is_null()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100355 Handle<SerializedScopeInfo> scope_info =
356 SerializedScopeInfo::Create(info->scope());
357 info->shared_info()->set_scope_info(*scope_info);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100358 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100359 return succeeded;
Steve Block6ded16b2010-05-10 14:33:55 +0100360}
361#endif
362
363
Ben Murdochf87a2032010-10-22 12:50:53 +0100364static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
366
367 PostponeInterruptsScope postpone;
368
369 ASSERT(!i::Top::global_context().is_null());
Ben Murdochf87a2032010-10-22 12:50:53 +0100370 Handle<Script> script = info->script();
Steve Blocka7e24c12009-10-30 11:49:00 +0000371 script->set_context_data((*i::Top::global_context())->data());
372
Leon Clarke4515c472010-02-03 11:58:03 +0000373#ifdef ENABLE_DEBUGGER_SUPPORT
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800374 if (info->is_eval()) {
375 Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL;
Ben Murdochf87a2032010-10-22 12:50:53 +0100376 script->set_compilation_type(Smi::FromInt(compilation_type));
Steve Blocka7e24c12009-10-30 11:49:00 +0000377 // For eval scripts add information on the function from which eval was
378 // called.
Ben Murdochf87a2032010-10-22 12:50:53 +0100379 if (info->is_eval()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000380 StackTraceFrameIterator it;
381 if (!it.done()) {
382 script->set_eval_from_shared(
383 JSFunction::cast(it.frame()->function())->shared());
384 int offset = static_cast<int>(
385 it.frame()->pc() - it.frame()->code()->instruction_start());
386 script->set_eval_from_instructions_offset(Smi::FromInt(offset));
387 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 }
389 }
390
391 // Notify debugger
392 Debugger::OnBeforeCompile(script);
393#endif
394
395 // Only allow non-global compiles for eval.
Ben Murdochf87a2032010-10-22 12:50:53 +0100396 ASSERT(info->is_eval() || info->is_global());
Steve Blocka7e24c12009-10-30 11:49:00 +0000397
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800398 if (!ParserApi::Parse(info)) return Handle<SharedFunctionInfo>::null();
Steve Blocka7e24c12009-10-30 11:49:00 +0000399
Steve Blocka7e24c12009-10-30 11:49:00 +0000400 // Measure how long it takes to do the compilation; only take the
401 // rest of the function into account to avoid overlap with the
402 // parsing statistics.
Ben Murdochf87a2032010-10-22 12:50:53 +0100403 HistogramTimer* rate = info->is_eval()
Steve Blocka7e24c12009-10-30 11:49:00 +0000404 ? &Counters::compile_eval
405 : &Counters::compile;
406 HistogramTimerScope timer(rate);
407
408 // Compile the code.
Ben Murdochf87a2032010-10-22 12:50:53 +0100409 FunctionLiteral* lit = info->function();
410 LiveEditFunctionTracker live_edit_tracker(lit);
411 if (!MakeCode(info)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000412 Top::StackOverflow();
Steve Block6ded16b2010-05-10 14:33:55 +0100413 return Handle<SharedFunctionInfo>::null();
Steve Blocka7e24c12009-10-30 11:49:00 +0000414 }
415
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100416 // Allocate function.
Ben Murdochf87a2032010-10-22 12:50:53 +0100417 ASSERT(!info->code().is_null());
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100418 Handle<SharedFunctionInfo> result =
419 Factory::NewSharedFunctionInfo(
420 lit->name(),
421 lit->materialized_literal_count(),
422 info->code(),
423 SerializedScopeInfo::Create(info->scope()));
424
425 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
426 Compiler::SetFunctionInfo(result, lit, true, script);
427
Steve Block6ded16b2010-05-10 14:33:55 +0100428 if (script->name()->IsString()) {
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(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100434 *result,
Ben Murdochf87a2032010-10-22 12:50:53 +0100435 String::cast(script->name())));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100436 GDBJIT(AddCode(Handle<String>(String::cast(script->name())),
437 script,
438 info->code()));
Steve Block6ded16b2010-05-10 14:33:55 +0100439 } else {
440 PROFILE(CodeCreateEvent(
Ben Murdochf87a2032010-10-22 12:50:53 +0100441 info->is_eval()
442 ? Logger::EVAL_TAG
443 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
444 *info->code(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100445 *result,
446 Heap::empty_string()));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100447 GDBJIT(AddCode(Handle<String>(), script, info->code()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000448 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000449
Steve Blocka7e24c12009-10-30 11:49:00 +0000450 // Hint to the runtime system used when allocating space for initial
451 // property space by setting the expected number of properties for
452 // the instances of the function.
Steve Block6ded16b2010-05-10 14:33:55 +0100453 SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count());
Steve Blocka7e24c12009-10-30 11:49:00 +0000454
455#ifdef ENABLE_DEBUGGER_SUPPORT
456 // Notify debugger
Steve Block6ded16b2010-05-10 14:33:55 +0100457 Debugger::OnAfterCompile(script, Debugger::NO_AFTER_COMPILE_FLAGS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000458#endif
459
Steve Block6ded16b2010-05-10 14:33:55 +0100460 live_edit_tracker.RecordFunctionInfo(result, lit);
461
462 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000463}
464
465
Steve Block6ded16b2010-05-10 14:33:55 +0100466Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
467 Handle<Object> script_name,
468 int line_offset,
469 int column_offset,
470 v8::Extension* extension,
471 ScriptDataImpl* input_pre_data,
472 Handle<Object> script_data,
473 NativesFlag natives) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000474 int source_length = source->length();
475 Counters::total_load_size.Increment(source_length);
476 Counters::total_compile_size.Increment(source_length);
477
478 // The VM is in the COMPILER state until exiting this function.
479 VMState state(COMPILER);
480
481 // Do a lookup in the compilation cache but not for extensions.
Steve Block6ded16b2010-05-10 14:33:55 +0100482 Handle<SharedFunctionInfo> result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000483 if (extension == NULL) {
484 result = CompilationCache::LookupScript(source,
485 script_name,
486 line_offset,
487 column_offset);
488 }
489
490 if (result.is_null()) {
Steve Block59151502010-09-22 15:07:15 +0100491 // No cache entry found. Do pre-parsing, if it makes sense, and compile
492 // the script.
493 // Building preparse data that is only used immediately after is only a
494 // saving if we might skip building the AST for lazily compiled functions.
495 // I.e., preparse data isn't relevant when the lazy flag is off, and
496 // for small sources, odds are that there aren't many functions
497 // that would be compiled lazily anyway, so we skip the preparse step
498 // in that case too.
Steve Blocka7e24c12009-10-30 11:49:00 +0000499 ScriptDataImpl* pre_data = input_pre_data;
Steve Block59151502010-09-22 15:07:15 +0100500 if (pre_data == NULL
Steve Block59151502010-09-22 15:07:15 +0100501 && source_length >= FLAG_min_preparse_length) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100502 if (source->IsExternalTwoByteString()) {
503 ExternalTwoByteStringUC16CharacterStream stream(
504 Handle<ExternalTwoByteString>::cast(source), 0, source->length());
505 pre_data = ParserApi::PartialPreParse(&stream, extension);
506 } else {
507 GenericStringUC16CharacterStream stream(source, 0, source->length());
508 pre_data = ParserApi::PartialPreParse(&stream, extension);
509 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000510 }
511
512 // Create a script object describing the script to be compiled.
513 Handle<Script> script = Factory::NewScript(source);
Andrei Popescu31002712010-02-23 13:46:05 +0000514 if (natives == NATIVES_CODE) {
515 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
516 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000517 if (!script_name.is_null()) {
518 script->set_name(*script_name);
519 script->set_line_offset(Smi::FromInt(line_offset));
520 script->set_column_offset(Smi::FromInt(column_offset));
521 }
522
Andrei Popescu402d9372010-02-26 13:31:12 +0000523 script->set_data(script_data.is_null() ? Heap::undefined_value()
524 : *script_data);
525
Steve Blocka7e24c12009-10-30 11:49:00 +0000526 // Compile the function and add it to the cache.
Ben Murdochf87a2032010-10-22 12:50:53 +0100527 CompilationInfo info(script);
528 info.MarkAsGlobal();
529 info.SetExtension(extension);
530 info.SetPreParseData(pre_data);
531 result = MakeFunctionInfo(&info);
Steve Blocka7e24c12009-10-30 11:49:00 +0000532 if (extension == NULL && !result.is_null()) {
533 CompilationCache::PutScript(source, result);
534 }
535
536 // Get rid of the pre-parsing data (if necessary).
537 if (input_pre_data == NULL && pre_data != NULL) {
538 delete pre_data;
539 }
540 }
541
542 if (result.is_null()) Top::ReportPendingMessages();
543 return result;
544}
545
546
Steve Block6ded16b2010-05-10 14:33:55 +0100547Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
548 Handle<Context> context,
Steve Block1e0659c2011-05-24 12:43:12 +0100549 bool is_global,
550 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000551 int source_length = source->length();
552 Counters::total_eval_size.Increment(source_length);
553 Counters::total_compile_size.Increment(source_length);
554
555 // The VM is in the COMPILER state until exiting this function.
556 VMState state(COMPILER);
557
Ben Murdochf87a2032010-10-22 12:50:53 +0100558 // Do a lookup in the compilation cache; if the entry is not there, invoke
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800559 // the compiler and add the result to the cache.
Steve Block6ded16b2010-05-10 14:33:55 +0100560 Handle<SharedFunctionInfo> result;
Steve Block1e0659c2011-05-24 12:43:12 +0100561 result = CompilationCache::LookupEval(source,
562 context,
563 is_global,
564 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000565
566 if (result.is_null()) {
567 // Create a script object describing the script to be compiled.
568 Handle<Script> script = Factory::NewScript(source);
Ben Murdochf87a2032010-10-22 12:50:53 +0100569 CompilationInfo info(script);
570 info.MarkAsEval();
571 if (is_global) info.MarkAsGlobal();
Steve Block1e0659c2011-05-24 12:43:12 +0100572 if (strict_mode == kStrictMode) info.MarkAsStrict();
Ben Murdochf87a2032010-10-22 12:50:53 +0100573 info.SetCallingContext(context);
574 result = MakeFunctionInfo(&info);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800575 if (!result.is_null()) {
Steve Block1e0659c2011-05-24 12:43:12 +0100576 // If caller is strict mode, the result must be strict as well,
577 // but not the other way around. Consider:
578 // eval("'use strict'; ...");
579 ASSERT(strict_mode == kNonStrictMode || result->strict_mode());
Steve Blocka7e24c12009-10-30 11:49:00 +0000580 CompilationCache::PutEval(source, context, is_global, result);
581 }
582 }
583
584 return result;
585}
586
587
Leon Clarke4515c472010-02-03 11:58:03 +0000588bool Compiler::CompileLazy(CompilationInfo* info) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000589 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
590
591 // The VM is in the COMPILER state until exiting this function.
592 VMState state(COMPILER);
593
594 PostponeInterruptsScope postpone;
595
Leon Clarke4515c472010-02-03 11:58:03 +0000596 Handle<SharedFunctionInfo> shared = info->shared_info();
Ben Murdochf87a2032010-10-22 12:50:53 +0100597 int compiled_size = shared->end_position() - shared->start_position();
598 Counters::total_compile_size.Increment(compiled_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000599
Ben Murdochf87a2032010-10-22 12:50:53 +0100600 // Generate the AST for the lazily compiled function.
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800601 if (ParserApi::Parse(info)) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100602 // Measure how long it takes to do the lazy compilation; only take the
603 // rest of the function into account to avoid overlap with the lazy
604 // parsing statistics.
605 HistogramTimerScope timer(&Counters::compile_lazy);
Steve Blocka7e24c12009-10-30 11:49:00 +0000606
Ben Murdochf87a2032010-10-22 12:50:53 +0100607 // Compile the code.
608 if (!MakeCode(info)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100609 if (!Top::has_pending_exception()) {
610 Top::StackOverflow();
611 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100612 } else {
613 ASSERT(!info->code().is_null());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100614 Handle<Code> code = info->code();
615 Handle<JSFunction> function = info->closure();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100616 RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
Steve Blocka7e24c12009-10-30 11:49:00 +0000617
Ben Murdochb0fe1622011-05-05 13:52:32 +0100618 if (info->IsOptimizing()) {
619 function->ReplaceCode(*code);
620 } else {
621 // Update the shared function info with the compiled code and the
622 // scope info. Please note, that the order of the shared function
623 // info initialization is important since set_scope_info might
624 // trigger a GC, causing the ASSERT below to be invalid if the code
625 // was flushed. By settting the code object last we avoid this.
626 Handle<SerializedScopeInfo> scope_info =
627 SerializedScopeInfo::Create(info->scope());
628 shared->set_scope_info(*scope_info);
629 shared->set_code(*code);
630 if (!function.is_null()) {
631 function->ReplaceCode(*code);
632 ASSERT(!function->IsOptimized());
633 }
634
635 // Set the expected number of properties for instances.
636 FunctionLiteral* lit = info->function();
637 int expected = lit->expected_property_count();
638 SetExpectedNofPropertiesFromEstimate(shared, expected);
639
640 // Set the optimization hints after performing lazy compilation, as
641 // these are not set when the function is set up as a lazily
642 // compiled function.
643 shared->SetThisPropertyAssignmentsInfo(
644 lit->has_only_simple_this_property_assignments(),
645 *lit->this_property_assignments());
646
647 // Check the function has compiled code.
648 ASSERT(shared->is_compiled());
649 shared->set_code_age(0);
650
651 if (V8::UseCrankshaft() && info->AllowOptimize()) {
652 // If we're asked to always optimize, we compile the optimized
653 // version of the function right away - unless the debugger is
654 // active as it makes no sense to compile optimized code then.
655 if (FLAG_always_opt && !Debug::has_break_points()) {
656 CompilationInfo optimized(function);
657 optimized.SetOptimizing(AstNode::kNoNumber);
658 return CompileLazy(&optimized);
659 } else if (CompilationCache::ShouldOptimizeEagerly(function)) {
660 RuntimeProfiler::OptimizeSoon(*function);
661 }
662 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100663 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000664
Ben Murdochf87a2032010-10-22 12:50:53 +0100665 return true;
666 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000667 }
668
Ben Murdochf87a2032010-10-22 12:50:53 +0100669 ASSERT(info->code().is_null());
670 return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000671}
672
673
Steve Block6ded16b2010-05-10 14:33:55 +0100674Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
Ben Murdochf87a2032010-10-22 12:50:53 +0100675 Handle<Script> script) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100676 // Precondition: code has been parsed and scopes have been analyzed.
677 CompilationInfo info(script);
678 info.SetFunction(literal);
679 info.SetScope(literal->scope());
680
681 LiveEditFunctionTracker live_edit_tracker(literal);
682 // Determine if the function can be lazily compiled. This is necessary to
683 // allow some of our builtin JS files to be lazily compiled. These
684 // builtins cannot be handled lazily by the parser, since we have to know
685 // if a function uses the special natives syntax, which is something the
686 // parser records.
Andrei Popescu402d9372010-02-26 13:31:12 +0000687 bool allow_lazy = literal->AllowsLazyCompilation() &&
688 !LiveEditFunctionTracker::IsActive();
Steve Blockd0582a62009-12-15 09:54:21 +0000689
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100690 Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty());
691
Steve Blockd0582a62009-12-15 09:54:21 +0000692 // Generate code
Steve Blockd0582a62009-12-15 09:54:21 +0000693 if (FLAG_lazy && allow_lazy) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100694 Handle<Code> code(Builtins::builtin(Builtins::LazyCompile));
695 info.SetCode(code);
Steve Blockd0582a62009-12-15 09:54:21 +0000696 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100697 if (V8::UseCrankshaft()) {
698 if (!MakeCrankshaftCode(&info)) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100699 return Handle<SharedFunctionInfo>::null();
700 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100701 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100702 // The bodies of function literals have not yet been visited by the
703 // AST optimizer/analyzer.
704 if (!Rewriter::Analyze(&info)) return Handle<SharedFunctionInfo>::null();
705
706 bool is_run_once = literal->try_full_codegen();
707 bool can_use_full = FLAG_full_compiler && !literal->contains_loops();
708
709 if (AlwaysFullCompiler() || (is_run_once && can_use_full)) {
710 if (!FullCodeGenerator::MakeCode(&info)) {
711 return Handle<SharedFunctionInfo>::null();
712 }
713 } else {
714 // We fall back to the classic V8 code generator.
715 if (!AssignedVariablesAnalyzer::Analyze(&info) ||
716 !CodeGenerator::MakeCode(&info)) {
717 return Handle<SharedFunctionInfo>::null();
718 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100719 }
Steve Blockd0582a62009-12-15 09:54:21 +0000720 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100721 ASSERT(!info.code().is_null());
Steve Blockd0582a62009-12-15 09:54:21 +0000722
723 // Function compilation complete.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100724 scope_info = SerializedScopeInfo::Create(info.scope());
Steve Blockd0582a62009-12-15 09:54:21 +0000725 }
726
Steve Block6ded16b2010-05-10 14:33:55 +0100727 // Create a shared function info object.
728 Handle<SharedFunctionInfo> result =
729 Factory::NewSharedFunctionInfo(literal->name(),
730 literal->materialized_literal_count(),
Ben Murdochf87a2032010-10-22 12:50:53 +0100731 info.code(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100732 scope_info);
Steve Block6ded16b2010-05-10 14:33:55 +0100733 SetFunctionInfo(result, literal, false, script);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100734 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100735 result->set_allows_lazy_compilation(allow_lazy);
Steve Blockd0582a62009-12-15 09:54:21 +0000736
737 // Set the expected number of properties for instances and return
738 // the resulting function.
Steve Block6ded16b2010-05-10 14:33:55 +0100739 SetExpectedNofPropertiesFromEstimate(result,
Steve Blockd0582a62009-12-15 09:54:21 +0000740 literal->expected_property_count());
Steve Block6ded16b2010-05-10 14:33:55 +0100741 live_edit_tracker.RecordFunctionInfo(result, literal);
742 return result;
Steve Blockd0582a62009-12-15 09:54:21 +0000743}
744
745
746// Sets the function info on a function.
747// The start_position points to the first '(' character after the function name
748// in the full script source. When counting characters in the script source the
749// the first character is number 0 (not 1).
Steve Block6ded16b2010-05-10 14:33:55 +0100750void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
Steve Blockd0582a62009-12-15 09:54:21 +0000751 FunctionLiteral* lit,
752 bool is_toplevel,
753 Handle<Script> script) {
Steve Block6ded16b2010-05-10 14:33:55 +0100754 function_info->set_length(lit->num_parameters());
755 function_info->set_formal_parameter_count(lit->num_parameters());
756 function_info->set_script(*script);
757 function_info->set_function_token_position(lit->function_token_position());
758 function_info->set_start_position(lit->start_position());
759 function_info->set_end_position(lit->end_position());
760 function_info->set_is_expression(lit->is_expression());
761 function_info->set_is_toplevel(is_toplevel);
762 function_info->set_inferred_name(*lit->inferred_name());
763 function_info->SetThisPropertyAssignmentsInfo(
Steve Blockd0582a62009-12-15 09:54:21 +0000764 lit->has_only_simple_this_property_assignments(),
765 *lit->this_property_assignments());
Steve Block6ded16b2010-05-10 14:33:55 +0100766 function_info->set_try_full_codegen(lit->try_full_codegen());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100767 function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
Steve Block1e0659c2011-05-24 12:43:12 +0100768 function_info->set_strict_mode(lit->strict_mode());
Steve Blockd0582a62009-12-15 09:54:21 +0000769}
770
771
Steve Block6ded16b2010-05-10 14:33:55 +0100772void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100773 CompilationInfo* info,
774 Handle<SharedFunctionInfo> shared) {
775 // SharedFunctionInfo is passed separately, because if CompilationInfo
776 // was created using Script object, it will not have it.
777
Ben Murdochf87a2032010-10-22 12:50:53 +0100778 // Log the code generation. If source information is available include
779 // script name and line number. Check explicitly whether logging is
780 // enabled as finding the line number is not free.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100781 if (Logger::is_logging() || CpuProfiler::is_profiling()) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100782 Handle<Script> script = info->script();
783 Handle<Code> code = info->code();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100784 if (*code == Builtins::builtin(Builtins::LazyCompile)) return;
Andrei Popescu31002712010-02-23 13:46:05 +0000785 if (script->name()->IsString()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100786 int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
Steve Block6ded16b2010-05-10 14:33:55 +0100787 USE(line_num);
788 PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
Ben Murdochf87a2032010-10-22 12:50:53 +0100789 *code,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100790 *shared,
Ben Murdochf87a2032010-10-22 12:50:53 +0100791 String::cast(script->name()),
792 line_num));
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,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100796 *shared,
797 shared->DebugName()));
Andrei Popescu31002712010-02-23 13:46:05 +0000798 }
799 }
Ben Murdochb8e0da22011-05-16 14:20:40 +0100800
801 GDBJIT(AddCode(name,
802 Handle<Script>(info->script()),
803 Handle<Code>(info->code())));
Andrei Popescu31002712010-02-23 13:46:05 +0000804}
Andrei Popescu31002712010-02-23 13:46:05 +0000805
Steve Blocka7e24c12009-10-30 11:49:00 +0000806} } // namespace v8::internal