blob: dce881639b78deb0244d303746c81ca2f8dc86b9 [file] [log] [blame]
ager@chromium.org71daaf62009-04-01 07:22:49 +00001// Copyright 2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
30#include "bootstrapper.h"
31#include "codegen-inl.h"
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000032#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "compiler.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000034#include "data-flow.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "debug.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000036#include "fast-codegen.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000037#include "full-codegen.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000038#include "liveedit.h"
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000039#include "oprofile-agent.h"
ager@chromium.org71daaf62009-04-01 07:22:49 +000040#include "rewriter.h"
41#include "scopes.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042
kasperl@chromium.org71affb52009-05-26 05:44:31 +000043namespace v8 {
44namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000046
ager@chromium.org5c838252010-02-19 08:53:10 +000047static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) {
48 FunctionLiteral* function = info->function();
49 ASSERT(function != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050 // Rewrite the AST by introducing .result assignments where needed.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000051 if (!Rewriter::Process(function)) {
kasper.lund212ac232008-07-16 07:07:30 +000052 // Signal a stack overflow by returning a null handle. The stack
53 // overflow exception will be thrown by the caller.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054 return Handle<Code>::null();
55 }
56
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000057 {
58 // Compute top scope and allocate variables. For lazy compilation
59 // the top scope only contains the single lazily compiled function,
60 // so this doesn't re-allocate variables repeatedly.
61 HistogramTimerScope timer(&Counters::variable_allocation);
ager@chromium.org5c838252010-02-19 08:53:10 +000062 Scope* top = info->scope();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000063 while (top->outer_scope() != NULL) top = top->outer_scope();
64 top->AllocateVariables(context);
65 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066
67#ifdef DEBUG
68 if (Bootstrapper::IsActive() ?
69 FLAG_print_builtin_scopes :
70 FLAG_print_scopes) {
ager@chromium.org5c838252010-02-19 08:53:10 +000071 info->scope()->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072 }
73#endif
74
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000075 // Optimize the AST.
ager@chromium.org5c838252010-02-19 08:53:10 +000076 if (!Rewriter::Optimize(function)) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +000077 // Signal a stack overflow by returning a null handle. The stack
78 // overflow exception will be thrown by the caller.
79 return Handle<Code>::null();
80 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000081
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000082 if (function->scope()->num_parameters() > 0 ||
83 function->scope()->num_stack_slots()) {
84 AssignedVariablesAnalyzer ava(function);
85 ava.Analyze();
86 if (ava.HasStackOverflow()) {
87 return Handle<Code>::null();
88 }
89 }
90
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000091 if (FLAG_use_flow_graph) {
92 FlowGraphBuilder builder;
93 builder.Build(function);
94
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000095 if (!builder.HasStackOverflow()) {
96 int variable_count =
97 function->num_parameters() + function->scope()->num_stack_slots();
98 if (variable_count > 0 && builder.definitions()->length() > 0) {
99 ReachingDefinitions rd(builder.postorder(),
100 builder.definitions(),
101 variable_count);
102 rd.Compute();
103 }
104 }
105
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000106#ifdef DEBUG
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000107 if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000108 builder.graph()->PrintText(builder.postorder());
109 }
110#endif
111 }
112
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000113 // Generate code and return it. Code generator selection is governed by
114 // which backends are enabled and whether the function is considered
115 // run-once code or not:
116 //
117 // --full-compiler enables the dedicated backend for code we expect to be
118 // run once
119 // --fast-compiler enables a speculative optimizing backend (for
120 // non-run-once code)
121 //
122 // The normal choice of backend can be overridden with the flags
123 // --always-full-compiler and --always-fast-compiler, which are mutually
124 // incompatible.
125 CHECK(!FLAG_always_full_compiler || !FLAG_always_fast_compiler);
126
127 Handle<SharedFunctionInfo> shared = info->shared_info();
128 bool is_run_once = (shared.is_null())
ager@chromium.org5c838252010-02-19 08:53:10 +0000129 ? info->scope()->is_global_scope()
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000130 : (shared->is_toplevel() || shared->try_full_codegen());
131
132 if (FLAG_always_full_compiler || (FLAG_full_compiler && is_run_once)) {
133 FullCodeGenSyntaxChecker checker;
ager@chromium.org5c838252010-02-19 08:53:10 +0000134 checker.Check(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000135 if (checker.has_supported_syntax()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000136 return FullCodeGenerator::MakeCode(info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 }
138 } else if (FLAG_always_fast_compiler ||
139 (FLAG_fast_compiler && !is_run_once)) {
140 FastCodeGenSyntaxChecker checker;
ager@chromium.org5c838252010-02-19 08:53:10 +0000141 checker.Check(info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000142 if (checker.has_supported_syntax()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000143 return FastCodeGenerator::MakeCode(info);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000144 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000145 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000146
ager@chromium.org5c838252010-02-19 08:53:10 +0000147 return CodeGenerator::MakeCode(info);
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000148}
149
150
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000151#ifdef ENABLE_DEBUGGER_SUPPORT
152Handle<Code> MakeCodeForLiveEdit(CompilationInfo* info) {
153 Handle<Context> context = Handle<Context>::null();
154 return MakeCode(context, info);
155}
156#endif
157
158
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159static Handle<JSFunction> MakeFunction(bool is_global,
160 bool is_eval,
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000161 Compiler::ValidationState validate,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162 Handle<Script> script,
ager@chromium.org381abbb2009-02-25 13:23:22 +0000163 Handle<Context> context,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000164 v8::Extension* extension,
165 ScriptDataImpl* pre_data) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000166 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000167
kasper.lund44510672008-07-25 07:37:58 +0000168 PostponeInterruptsScope postpone;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000169
ager@chromium.org9085a012009-05-11 19:22:57 +0000170 ASSERT(!i::Top::global_context().is_null());
171 script->set_context_data((*i::Top::global_context())->data());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000172
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000173 bool is_json = (validate == Compiler::VALIDATE_JSON);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000174#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.orge2902be2009-06-08 12:21:35 +0000175 if (is_eval || is_json) {
176 script->set_compilation_type(
177 is_json ? Smi::FromInt(Script::COMPILATION_TYPE_JSON) :
178 Smi::FromInt(Script::COMPILATION_TYPE_EVAL));
179 // For eval scripts add information on the function from which eval was
180 // called.
181 if (is_eval) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000182 StackTraceFrameIterator it;
183 if (!it.done()) {
184 script->set_eval_from_shared(
185 JSFunction::cast(it.frame()->function())->shared());
186 int offset = static_cast<int>(
187 it.frame()->pc() - it.frame()->code()->instruction_start());
188 script->set_eval_from_instructions_offset(Smi::FromInt(offset));
189 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000190 }
191 }
192
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193 // Notify debugger
194 Debugger::OnBeforeCompile(script);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000195#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000196
197 // Only allow non-global compiles for eval.
198 ASSERT(is_eval || is_global);
199
200 // Build AST.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000201 FunctionLiteral* lit =
202 MakeAST(is_global, script, extension, pre_data, is_json);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203
kasper.lund212ac232008-07-16 07:07:30 +0000204 // Check for parse errors.
205 if (lit == NULL) {
206 ASSERT(Top::has_pending_exception());
kasper.lund212ac232008-07-16 07:07:30 +0000207 return Handle<JSFunction>::null();
208 }
209
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210 // Measure how long it takes to do the compilation; only take the
211 // rest of the function into account to avoid overlap with the
212 // parsing statistics.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000213 HistogramTimer* rate = is_eval
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214 ? &Counters::compile_eval
215 : &Counters::compile;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000216 HistogramTimerScope timer(rate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217
218 // Compile the code.
ager@chromium.org5c838252010-02-19 08:53:10 +0000219 CompilationInfo info(lit, script, is_eval);
220 Handle<Code> code = MakeCode(context, &info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000221
kasper.lund212ac232008-07-16 07:07:30 +0000222 // Check for stack-overflow exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000223 if (code.is_null()) {
kasper.lund212ac232008-07-16 07:07:30 +0000224 Top::StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225 return Handle<JSFunction>::null();
226 }
227
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000228#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
iposva@chromium.org245aa852009-02-10 00:49:54 +0000229 // Log the code generation for the script. Check explicit whether logging is
230 // to avoid allocating when not required.
ager@chromium.org3e875802009-06-29 08:26:34 +0000231 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000232 if (script->name()->IsString()) {
233 SmartPointer<char> data =
234 String::cast(script->name())->ToCString(DISALLOW_NULLS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000235 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
236 *code, *data));
237 OProfileAgent::CreateNativeCodeRegion(*data,
238 code->instruction_start(),
239 code->instruction_size());
iposva@chromium.org245aa852009-02-10 00:49:54 +0000240 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000241 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
242 *code, ""));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000243 OProfileAgent::CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000244 code->instruction_start(),
245 code->instruction_size());
iposva@chromium.org245aa852009-02-10 00:49:54 +0000246 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247 }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000248#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000249
250 // Allocate function.
251 Handle<JSFunction> fun =
252 Factory::NewFunctionBoilerplate(lit->name(),
253 lit->materialized_literal_count(),
254 code);
255
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000256 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000257 Compiler::SetFunctionInfo(fun, lit, true, script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000258
259 // Hint to the runtime system used when allocating space for initial
260 // property space by setting the expected number of properties for
261 // the instances of the function.
262 SetExpectedNofPropertiesFromEstimate(fun, lit->expected_property_count());
263
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000264#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 // Notify debugger
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000266 Debugger::OnAfterCompile(script, Debugger::NO_AFTER_COMPILE_FLAGS);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000267#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268
269 return fun;
270}
271
272
273static StaticResource<SafeStringInputBuffer> safe_string_input_buffer;
274
275
276Handle<JSFunction> Compiler::Compile(Handle<String> source,
mads.s.agercbaa0602008-08-14 13:41:48 +0000277 Handle<Object> script_name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000278 int line_offset, int column_offset,
279 v8::Extension* extension,
ager@chromium.org5c838252010-02-19 08:53:10 +0000280 ScriptDataImpl* input_pre_data,
281 Handle<Object> script_data) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000282 int source_length = source->length();
283 Counters::total_load_size.Increment(source_length);
284 Counters::total_compile_size.Increment(source_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000285
286 // The VM is in the COMPILER state until exiting this function.
287 VMState state(COMPILER);
288
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000289 // Do a lookup in the compilation cache but not for extensions.
290 Handle<JSFunction> result;
291 if (extension == NULL) {
292 result = CompilationCache::LookupScript(source,
293 script_name,
294 line_offset,
295 column_offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000296 }
297
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000298 if (result.is_null()) {
299 // No cache entry found. Do pre-parsing and compile the script.
300 ScriptDataImpl* pre_data = input_pre_data;
ager@chromium.org870a0b62008-11-04 11:43:05 +0000301 if (pre_data == NULL && source_length >= FLAG_min_preparse_length) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000302 Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
303 buf->Reset(source.location());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000304 pre_data = PreParse(source, buf.value(), extension);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000305 }
306
307 // Create a script object describing the script to be compiled.
308 Handle<Script> script = Factory::NewScript(source);
309 if (!script_name.is_null()) {
310 script->set_name(*script_name);
311 script->set_line_offset(Smi::FromInt(line_offset));
312 script->set_column_offset(Smi::FromInt(column_offset));
313 }
314
ager@chromium.org5c838252010-02-19 08:53:10 +0000315 script->set_data(script_data.is_null() ? Heap::undefined_value()
316 : *script_data);
317
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000318 // Compile the function and add it to the cache.
ager@chromium.org381abbb2009-02-25 13:23:22 +0000319 result = MakeFunction(true,
320 false,
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000321 DONT_VALIDATE_JSON,
ager@chromium.org381abbb2009-02-25 13:23:22 +0000322 script,
323 Handle<Context>::null(),
324 extension,
325 pre_data);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000326 if (extension == NULL && !result.is_null()) {
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +0000327 CompilationCache::PutScript(source, result);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000328 }
329
330 // Get rid of the pre-parsing data (if necessary).
331 if (input_pre_data == NULL && pre_data != NULL) {
332 delete pre_data;
333 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334 }
335
ager@chromium.org8bb60582008-12-11 12:02:20 +0000336 if (result.is_null()) Top::ReportPendingMessages();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337 return result;
338}
339
340
ager@chromium.org236ad962008-09-25 09:45:57 +0000341Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
ager@chromium.org381abbb2009-02-25 13:23:22 +0000342 Handle<Context> context,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000343 bool is_global,
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000344 ValidationState validate) {
345 // Note that if validation is required then no path through this
346 // function is allowed to return a value without validating that
347 // the input is legal json.
348
ager@chromium.orgc3e50d82008-11-05 11:53:10 +0000349 int source_length = source->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000350 Counters::total_eval_size.Increment(source_length);
351 Counters::total_compile_size.Increment(source_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000352
353 // The VM is in the COMPILER state until exiting this function.
354 VMState state(COMPILER);
355
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000356 // Do a lookup in the compilation cache; if the entry is not there,
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000357 // invoke the compiler and add the result to the cache. If we're
358 // evaluating json we bypass the cache since we can't be sure a
359 // potential value in the cache has been validated.
360 Handle<JSFunction> result;
361 if (validate == DONT_VALIDATE_JSON)
362 result = CompilationCache::LookupEval(source, context, is_global);
363
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000364 if (result.is_null()) {
365 // Create a script object describing the script to be compiled.
366 Handle<Script> script = Factory::NewScript(source);
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000367 result = MakeFunction(is_global,
368 true,
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000369 validate,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000370 script,
371 context,
372 NULL,
373 NULL);
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000374 if (!result.is_null() && validate != VALIDATE_JSON) {
375 // For json it's unlikely that we'll ever see exactly the same
376 // string again so we don't use the compilation cache.
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000377 CompilationCache::PutEval(source, context, is_global, result);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000378 }
379 }
ager@chromium.org8bb60582008-12-11 12:02:20 +0000380
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000381 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000382}
383
384
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000385bool Compiler::CompileLazy(CompilationInfo* info) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000386 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387
388 // The VM is in the COMPILER state until exiting this function.
389 VMState state(COMPILER);
390
kasper.lund44510672008-07-25 07:37:58 +0000391 PostponeInterruptsScope postpone;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000392
393 // Compute name, source code and script data.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000394 Handle<SharedFunctionInfo> shared = info->shared_info();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 Handle<String> name(String::cast(shared->name()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396
397 int start_position = shared->start_position();
398 int end_position = shared->end_position();
399 bool is_expression = shared->is_expression();
400 Counters::total_compile_size.Increment(end_position - start_position);
401
402 // Generate the AST for the lazily compiled function. The AST may be
403 // NULL in case of parser stack overflow.
ager@chromium.org5c838252010-02-19 08:53:10 +0000404 FunctionLiteral* lit = MakeLazyAST(info->script(),
405 name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000406 start_position,
407 end_position,
408 is_expression);
409
kasper.lund212ac232008-07-16 07:07:30 +0000410 // Check for parse errors.
411 if (lit == NULL) {
412 ASSERT(Top::has_pending_exception());
kasper.lund212ac232008-07-16 07:07:30 +0000413 return false;
414 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000415 info->set_function(lit);
kasper.lund212ac232008-07-16 07:07:30 +0000416
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 // Measure how long it takes to do the lazy compilation; only take
418 // the rest of the function into account to avoid overlap with the
419 // lazy parsing statistics.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000420 HistogramTimerScope timer(&Counters::compile_lazy);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000421
kasper.lund212ac232008-07-16 07:07:30 +0000422 // Compile the code.
ager@chromium.org5c838252010-02-19 08:53:10 +0000423 Handle<Code> code = MakeCode(Handle<Context>::null(), info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000424
kasper.lund212ac232008-07-16 07:07:30 +0000425 // Check for stack-overflow exception.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000426 if (code.is_null()) {
kasper.lund212ac232008-07-16 07:07:30 +0000427 Top::StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 return false;
429 }
430
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000431#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
ager@chromium.org5c838252010-02-19 08:53:10 +0000432 LogCodeCreateEvent(Logger::LAZY_COMPILE_TAG,
433 name,
434 Handle<String>(shared->inferred_name()),
435 start_position,
436 info->script(),
437 code);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000438#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439
440 // Update the shared function info with the compiled code.
441 shared->set_code(*code);
442
443 // Set the expected number of properties for instances.
444 SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
445
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000446 // Set the optimication hints after performing lazy compilation, as these are
447 // not set when the function is set up as a lazily compiled function.
448 shared->SetThisPropertyAssignmentsInfo(
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000449 lit->has_only_simple_this_property_assignments(),
450 *lit->this_property_assignments());
451
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000452 // Check the function has compiled code.
453 ASSERT(shared->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454 return true;
455}
456
457
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000458Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
459 Handle<Script> script,
460 AstVisitor* caller) {
461#ifdef DEBUG
462 // We should not try to compile the same function literal more than
463 // once.
464 literal->mark_as_compiled();
465#endif
466
467 // Determine if the function can be lazily compiled. This is
468 // necessary to allow some of our builtin JS files to be lazily
469 // compiled. These builtins cannot be handled lazily by the parser,
470 // since we have to know if a function uses the special natives
471 // syntax, which is something the parser records.
ager@chromium.org5c838252010-02-19 08:53:10 +0000472 bool allow_lazy = literal->AllowsLazyCompilation() &&
473 !LiveEditFunctionTracker::IsActive();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000474
475 // Generate code
476 Handle<Code> code;
477 if (FLAG_lazy && allow_lazy) {
478 code = ComputeLazyCompile(literal->num_parameters());
479 } else {
480 // The bodies of function literals have not yet been visited by
481 // the AST optimizer/analyzer.
482 if (!Rewriter::Optimize(literal)) {
483 return Handle<JSFunction>::null();
484 }
485
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000486 if (literal->scope()->num_parameters() > 0 ||
487 literal->scope()->num_stack_slots()) {
488 AssignedVariablesAnalyzer ava(literal);
489 ava.Analyze();
490 if (ava.HasStackOverflow()) {
491 return Handle<JSFunction>::null();
492 }
493 }
494
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000495 if (FLAG_use_flow_graph) {
496 FlowGraphBuilder builder;
497 builder.Build(literal);
498
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000499 if (!builder.HasStackOverflow()) {
500 int variable_count =
501 literal->num_parameters() + literal->scope()->num_stack_slots();
502 if (variable_count > 0 && builder.definitions()->length() > 0) {
503 ReachingDefinitions rd(builder.postorder(),
504 builder.definitions(),
505 variable_count);
506 rd.Compute();
507 }
508 }
509
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000510#ifdef DEBUG
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000511 if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000512 builder.graph()->PrintText(builder.postorder());
513 }
514#endif
515 }
516
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000517 // Generate code and return it. The way that the compilation mode
518 // is controlled by the command-line flags is described in
519 // the static helper function MakeCode.
ager@chromium.org5c838252010-02-19 08:53:10 +0000520 CompilationInfo info(literal, script, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000521
522 CHECK(!FLAG_always_full_compiler || !FLAG_always_fast_compiler);
523 bool is_run_once = literal->try_full_codegen();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000524 bool is_compiled = false;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000525 if (FLAG_always_full_compiler || (FLAG_full_compiler && is_run_once)) {
526 FullCodeGenSyntaxChecker checker;
527 checker.Check(literal);
528 if (checker.has_supported_syntax()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000529 code = FullCodeGenerator::MakeCode(&info);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000530 is_compiled = true;
531 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000532 } else if (FLAG_always_fast_compiler ||
533 (FLAG_fast_compiler && !is_run_once)) {
534 // Since we are not lazily compiling we do not have a receiver to
535 // specialize for.
536 FastCodeGenSyntaxChecker checker;
ager@chromium.org5c838252010-02-19 08:53:10 +0000537 checker.Check(&info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000538 if (checker.has_supported_syntax()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000539 code = FastCodeGenerator::MakeCode(&info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000540 is_compiled = true;
541 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000542 }
543
544 if (!is_compiled) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000545 // We fall back to the classic V8 code generator.
ager@chromium.org5c838252010-02-19 08:53:10 +0000546 code = CodeGenerator::MakeCode(&info);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000547 }
548
549 // Check for stack-overflow exception.
550 if (code.is_null()) {
551 caller->SetStackOverflow();
552 return Handle<JSFunction>::null();
553 }
554
555 // Function compilation complete.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000556
ager@chromium.org5c838252010-02-19 08:53:10 +0000557#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
558 LogCodeCreateEvent(Logger::FUNCTION_TAG,
559 literal->name(),
560 literal->inferred_name(),
561 literal->start_position(),
562 script,
563 code);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000564#endif
565 }
566
567 // Create a boilerplate function.
568 Handle<JSFunction> function =
569 Factory::NewFunctionBoilerplate(literal->name(),
570 literal->materialized_literal_count(),
571 code);
572 SetFunctionInfo(function, literal, false, script);
573
574#ifdef ENABLE_DEBUGGER_SUPPORT
575 // Notify debugger that a new function has been added.
576 Debugger::OnNewFunction(function);
577#endif
578
579 // Set the expected number of properties for instances and return
580 // the resulting function.
581 SetExpectedNofPropertiesFromEstimate(function,
582 literal->expected_property_count());
583 return function;
584}
585
586
587// Sets the function info on a function.
588// The start_position points to the first '(' character after the function name
589// in the full script source. When counting characters in the script source the
590// the first character is number 0 (not 1).
591void Compiler::SetFunctionInfo(Handle<JSFunction> fun,
592 FunctionLiteral* lit,
593 bool is_toplevel,
594 Handle<Script> script) {
595 fun->shared()->set_length(lit->num_parameters());
596 fun->shared()->set_formal_parameter_count(lit->num_parameters());
597 fun->shared()->set_script(*script);
598 fun->shared()->set_function_token_position(lit->function_token_position());
599 fun->shared()->set_start_position(lit->start_position());
600 fun->shared()->set_end_position(lit->end_position());
601 fun->shared()->set_is_expression(lit->is_expression());
602 fun->shared()->set_is_toplevel(is_toplevel);
603 fun->shared()->set_inferred_name(*lit->inferred_name());
604 fun->shared()->SetThisPropertyAssignmentsInfo(
605 lit->has_only_simple_this_property_assignments(),
606 *lit->this_property_assignments());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000607 fun->shared()->set_try_full_codegen(lit->try_full_codegen());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000608}
609
610
ager@chromium.org5c838252010-02-19 08:53:10 +0000611#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
612void Compiler::LogCodeCreateEvent(Logger::LogEventsAndTags tag,
613 Handle<String> name,
614 Handle<String> inferred_name,
615 int start_position,
616 Handle<Script> script,
617 Handle<Code> code) {
618 // Log the code generation. If source information is available
619 // include script name and line number. Check explicitly whether
620 // logging is enabled as finding the line number is not free.
621 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
622 Handle<String> func_name(name->length() > 0 ? *name : *inferred_name);
623 if (script->name()->IsString()) {
624 int line_num = GetScriptLineNumber(script, start_position) + 1;
625 LOG(CodeCreateEvent(tag, *code, *func_name,
626 String::cast(script->name()), line_num));
627 OProfileAgent::CreateNativeCodeRegion(*func_name,
628 String::cast(script->name()),
629 line_num,
630 code->instruction_start(),
631 code->instruction_size());
632 } else {
633 LOG(CodeCreateEvent(tag, *code, *func_name));
634 OProfileAgent::CreateNativeCodeRegion(*func_name,
635 code->instruction_start(),
636 code->instruction_size());
637 }
638 }
639}
640#endif
641
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642} } // namespace v8::internal