blob: 29bbbc7034e92deef346bb0d85e7c3e2aad4e4f8 [file] [log] [blame]
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00001// Copyright 2010 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
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000030#include "compiler.h"
31
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "bootstrapper.h"
33#include "codegen-inl.h"
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000034#include "compilation-cache.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000035#include "data-flow.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "debug.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"
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000040#include "parser.h"
ager@chromium.org71daaf62009-04-01 07:22:49 +000041#include "rewriter.h"
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000042#include "scopeinfo.h"
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000043#include "scopes.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044
kasperl@chromium.org71affb52009-05-26 05:44:31 +000045namespace v8 {
46namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000048
49CompilationInfo::CompilationInfo(Handle<Script> script)
50 : flags_(0),
51 function_(NULL),
52 scope_(NULL),
53 script_(script),
54 extension_(NULL),
55 pre_parse_data_(NULL) {
56}
57
58
59CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info)
60 : flags_(IsLazy::encode(true)),
61 function_(NULL),
62 scope_(NULL),
63 shared_info_(shared_info),
64 script_(Handle<Script>(Script::cast(shared_info->script()))),
65 extension_(NULL),
66 pre_parse_data_(NULL) {
67}
68
69
70CompilationInfo::CompilationInfo(Handle<JSFunction> closure)
71 : flags_(IsLazy::encode(true)),
72 function_(NULL),
73 scope_(NULL),
74 closure_(closure),
75 shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
76 script_(Handle<Script>(Script::cast(shared_info_->script()))),
77 extension_(NULL),
78 pre_parse_data_(NULL) {
79}
80
81
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000082// For normal operation the syntax checker is used to determine whether to
83// use the full compiler for top level code or not. However if the flag
84// --always-full-compiler is specified or debugging is active the full
85// compiler will be used for all code.
86static bool AlwaysFullCompiler() {
87#ifdef ENABLE_DEBUGGER_SUPPORT
88 return FLAG_always_full_compiler || Debugger::IsDebuggerActive();
89#else
90 return FLAG_always_full_compiler;
91#endif
92}
93
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000094
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000095static bool MakeCode(CompilationInfo* info) {
96 // Precondition: code has been parsed. Postcondition: the code field in
97 // the compilation info is set if compilation succeeded.
98 ASSERT(info->function() != NULL);
99
100 if (Rewriter::Rewrite(info) &&
101 Scope::Analyze(info) &&
102 Rewriter::Analyze(info)) {
103 // Generate code and return it. Code generator selection is governed by
104 // which backends are enabled and whether the function is considered
105 // run-once code or not.
106 //
107 // --full-compiler enables the dedicated backend for code we expect to
108 // be run once
109 //
110 // The normal choice of backend can be overridden with the flags
111 // --always-full-compiler.
112 Handle<SharedFunctionInfo> shared = info->shared_info();
113 bool is_run_once = (shared.is_null())
114 ? info->scope()->is_global_scope()
115 : (shared->is_toplevel() || shared->try_full_codegen());
116 bool can_use_full =
117 FLAG_full_compiler && !info->function()->contains_loops();
118 if (AlwaysFullCompiler() || (is_run_once && can_use_full)) {
119 return FullCodeGenerator::MakeCode(info);
120 } else {
121 AssignedVariablesAnalyzer ava;
122 return ava.Analyze(info) && CodeGenerator::MakeCode(info);
123 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124 }
125
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000126 return false;
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000127}
128
129
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000130#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000131bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) {
132 // Precondition: code has been parsed. Postcondition: the code field in
133 // the compilation info is set if compilation succeeded.
134 bool succeeded = MakeCode(info);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000135 if (!info->shared_info().is_null()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000136 Handle<SerializedScopeInfo> scope_info =
137 SerializedScopeInfo::Create(info->scope());
138 info->shared_info()->set_scope_info(*scope_info);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000139 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000140 return succeeded;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000141}
142#endif
143
144
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000145static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000146 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000147
kasper.lund44510672008-07-25 07:37:58 +0000148 PostponeInterruptsScope postpone;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149
ager@chromium.org9085a012009-05-11 19:22:57 +0000150 ASSERT(!i::Top::global_context().is_null());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000151 Handle<Script> script = info->script();
ager@chromium.org9085a012009-05-11 19:22:57 +0000152 script->set_context_data((*i::Top::global_context())->data());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000153
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154#ifdef ENABLE_DEBUGGER_SUPPORT
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000155 if (info->is_eval()) {
156 Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000157 script->set_compilation_type(Smi::FromInt(compilation_type));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000158 // For eval scripts add information on the function from which eval was
159 // called.
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000160 if (info->is_eval()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 StackTraceFrameIterator it;
162 if (!it.done()) {
163 script->set_eval_from_shared(
164 JSFunction::cast(it.frame()->function())->shared());
165 int offset = static_cast<int>(
166 it.frame()->pc() - it.frame()->code()->instruction_start());
167 script->set_eval_from_instructions_offset(Smi::FromInt(offset));
168 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000169 }
170 }
171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172 // Notify debugger
173 Debugger::OnBeforeCompile(script);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000174#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000175
176 // Only allow non-global compiles for eval.
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000177 ASSERT(info->is_eval() || info->is_global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000178
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000179 if (!ParserApi::Parse(info)) return Handle<SharedFunctionInfo>::null();
kasper.lund212ac232008-07-16 07:07:30 +0000180
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181 // Measure how long it takes to do the compilation; only take the
182 // rest of the function into account to avoid overlap with the
183 // parsing statistics.
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000184 HistogramTimer* rate = info->is_eval()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185 ? &Counters::compile_eval
186 : &Counters::compile;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000187 HistogramTimerScope timer(rate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000188
189 // Compile the code.
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000190 FunctionLiteral* lit = info->function();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000191 LiveEditFunctionTracker live_edit_tracker(lit);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000192 if (!MakeCode(info)) {
kasper.lund212ac232008-07-16 07:07:30 +0000193 Top::StackOverflow();
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000194 return Handle<SharedFunctionInfo>::null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000195 }
196
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000197 ASSERT(!info->code().is_null());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000198 if (script->name()->IsString()) {
ager@chromium.org357bf652010-04-12 11:30:10 +0000199 PROFILE(CodeCreateEvent(
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000200 info->is_eval()
201 ? Logger::EVAL_TAG
202 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
203 *info->code(),
204 String::cast(script->name())));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000205 OPROFILE(CreateNativeCodeRegion(String::cast(script->name()),
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000206 info->code()->instruction_start(),
207 info->code()->instruction_size()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000208 } else {
ager@chromium.org357bf652010-04-12 11:30:10 +0000209 PROFILE(CodeCreateEvent(
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000210 info->is_eval()
211 ? Logger::EVAL_TAG
212 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
213 *info->code(),
214 ""));
215 OPROFILE(CreateNativeCodeRegion(info->is_eval() ? "Eval" : "Script",
216 info->code()->instruction_start(),
217 info->code()->instruction_size()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218 }
219
220 // Allocate function.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000221 Handle<SharedFunctionInfo> result =
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000222 Factory::NewSharedFunctionInfo(
223 lit->name(),
224 lit->materialized_literal_count(),
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000225 info->code(),
226 SerializedScopeInfo::Create(info->scope()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000228 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000229 Compiler::SetFunctionInfo(result, lit, true, script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230
231 // Hint to the runtime system used when allocating space for initial
232 // property space by setting the expected number of properties for
233 // the instances of the function.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000234 SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000236#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237 // Notify debugger
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000238 Debugger::OnAfterCompile(script, Debugger::NO_AFTER_COMPILE_FLAGS);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000239#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000241 live_edit_tracker.RecordFunctionInfo(result, lit);
242
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000243 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000244}
245
246
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000247Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
248 Handle<Object> script_name,
249 int line_offset,
250 int column_offset,
251 v8::Extension* extension,
252 ScriptDataImpl* input_pre_data,
253 Handle<Object> script_data,
254 NativesFlag natives) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000255 int source_length = source->length();
256 Counters::total_load_size.Increment(source_length);
257 Counters::total_compile_size.Increment(source_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000258
259 // The VM is in the COMPILER state until exiting this function.
260 VMState state(COMPILER);
261
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000262 // Do a lookup in the compilation cache but not for extensions.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000263 Handle<SharedFunctionInfo> result;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000264 if (extension == NULL) {
265 result = CompilationCache::LookupScript(source,
266 script_name,
267 line_offset,
268 column_offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000269 }
270
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000271 if (result.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000272 // No cache entry found. Do pre-parsing, if it makes sense, and compile
273 // the script.
274 // Building preparse data that is only used immediately after is only a
275 // saving if we might skip building the AST for lazily compiled functions.
276 // I.e., preparse data isn't relevant when the lazy flag is off, and
277 // for small sources, odds are that there aren't many functions
278 // that would be compiled lazily anyway, so we skip the preparse step
279 // in that case too.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000280 ScriptDataImpl* pre_data = input_pre_data;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000281 if (pre_data == NULL
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000282 && source_length >= FLAG_min_preparse_length) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000283 pre_data = ParserApi::PartialPreParse(source, NULL, extension);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000284 }
285
286 // Create a script object describing the script to be compiled.
287 Handle<Script> script = Factory::NewScript(source);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000288 if (natives == NATIVES_CODE) {
289 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
290 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000291 if (!script_name.is_null()) {
292 script->set_name(*script_name);
293 script->set_line_offset(Smi::FromInt(line_offset));
294 script->set_column_offset(Smi::FromInt(column_offset));
295 }
296
ager@chromium.org5c838252010-02-19 08:53:10 +0000297 script->set_data(script_data.is_null() ? Heap::undefined_value()
298 : *script_data);
299
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000300 // Compile the function and add it to the cache.
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000301 CompilationInfo info(script);
302 info.MarkAsGlobal();
303 info.SetExtension(extension);
304 info.SetPreParseData(pre_data);
305 result = MakeFunctionInfo(&info);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000306 if (extension == NULL && !result.is_null()) {
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +0000307 CompilationCache::PutScript(source, result);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000308 }
309
310 // Get rid of the pre-parsing data (if necessary).
311 if (input_pre_data == NULL && pre_data != NULL) {
312 delete pre_data;
313 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314 }
315
ager@chromium.org8bb60582008-12-11 12:02:20 +0000316 if (result.is_null()) Top::ReportPendingMessages();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 return result;
318}
319
320
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000321Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
322 Handle<Context> context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000323 bool is_global) {
ager@chromium.orgc3e50d82008-11-05 11:53:10 +0000324 int source_length = source->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000325 Counters::total_eval_size.Increment(source_length);
326 Counters::total_compile_size.Increment(source_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327
328 // The VM is in the COMPILER state until exiting this function.
329 VMState state(COMPILER);
330
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000331 // Do a lookup in the compilation cache; if the entry is not there, invoke
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000332 // the compiler and add the result to the cache.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000333 Handle<SharedFunctionInfo> result;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000334 result = CompilationCache::LookupEval(source, context, is_global);
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000335
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000336 if (result.is_null()) {
337 // Create a script object describing the script to be compiled.
338 Handle<Script> script = Factory::NewScript(source);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000339 CompilationInfo info(script);
340 info.MarkAsEval();
341 if (is_global) info.MarkAsGlobal();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000342 info.SetCallingContext(context);
343 result = MakeFunctionInfo(&info);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000344 if (!result.is_null()) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000345 CompilationCache::PutEval(source, context, is_global, result);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000346 }
347 }
ager@chromium.org8bb60582008-12-11 12:02:20 +0000348
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000349 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350}
351
352
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000353bool Compiler::CompileLazy(CompilationInfo* info) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000354 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355
356 // The VM is in the COMPILER state until exiting this function.
357 VMState state(COMPILER);
358
kasper.lund44510672008-07-25 07:37:58 +0000359 PostponeInterruptsScope postpone;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000361 Handle<SharedFunctionInfo> shared = info->shared_info();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000362 int compiled_size = shared->end_position() - shared->start_position();
363 Counters::total_compile_size.Increment(compiled_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000365 // Generate the AST for the lazily compiled function.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000366 if (ParserApi::Parse(info)) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000367 // Measure how long it takes to do the lazy compilation; only take the
368 // rest of the function into account to avoid overlap with the lazy
369 // parsing statistics.
370 HistogramTimerScope timer(&Counters::compile_lazy);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000371
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000372 // Compile the code.
373 if (!MakeCode(info)) {
374 Top::StackOverflow();
375 } else {
376 ASSERT(!info->code().is_null());
377 RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG,
378 Handle<String>(shared->DebugName()),
379 shared->start_position(),
380 info);
kasper.lund212ac232008-07-16 07:07:30 +0000381
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000382 // Update the shared function info with the compiled code and the
383 // scope info. Please note, that the order of the sharedfunction
384 // initialization is important since SerializedScopeInfo::Create might
385 // trigger a GC, causing the ASSERT below to be invalid if the code
386 // was flushed. By setting the code object last we avoid this.
387 Handle<SerializedScopeInfo> scope_info =
388 SerializedScopeInfo::Create(info->scope());
389 shared->set_scope_info(*scope_info);
390 shared->set_code(*info->code());
391 if (!info->closure().is_null()) {
392 info->closure()->set_code(*info->code());
393 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000395 // Set the expected number of properties for instances.
396 FunctionLiteral* lit = info->function();
397 SetExpectedNofPropertiesFromEstimate(shared,
398 lit->expected_property_count());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000400 // Set the optimization hints after performing lazy compilation, as
401 // these are not set when the function is set up as a lazily compiled
402 // function.
403 shared->SetThisPropertyAssignmentsInfo(
404 lit->has_only_simple_this_property_assignments(),
405 *lit->this_property_assignments());
406
407 // Check the function has compiled code.
408 ASSERT(shared->is_compiled());
409 shared->set_code_age(0);
410 ASSERT(!info->code().is_null());
411 return true;
412 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 }
414
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000415 ASSERT(info->code().is_null());
416 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417}
418
419
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000420Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000421 Handle<Script> script) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000422#ifdef DEBUG
423 // We should not try to compile the same function literal more than
424 // once.
425 literal->mark_as_compiled();
426#endif
427
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000428 // Precondition: code has been parsed and scopes have been analyzed.
429 CompilationInfo info(script);
430 info.SetFunction(literal);
431 info.SetScope(literal->scope());
432
433 LiveEditFunctionTracker live_edit_tracker(literal);
434 // Determine if the function can be lazily compiled. This is necessary to
435 // allow some of our builtin JS files to be lazily compiled. These
436 // builtins cannot be handled lazily by the parser, since we have to know
437 // if a function uses the special natives syntax, which is something the
438 // parser records.
ager@chromium.org5c838252010-02-19 08:53:10 +0000439 bool allow_lazy = literal->AllowsLazyCompilation() &&
440 !LiveEditFunctionTracker::IsActive();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000441
ager@chromium.orgb5737492010-07-15 09:29:43 +0000442 Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000443
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000444 // Generate code
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000445 if (FLAG_lazy && allow_lazy) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000446 Handle<Code> code(Builtins::builtin(Builtins::LazyCompile));
447 info.SetCode(code);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000448 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000449 // Generate code and return it. The way that the compilation mode
450 // is controlled by the command-line flags is described in
451 // the static helper function MakeCode.
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000452 //
453 // The bodies of function literals have not yet been visited by
454 // the AST analyzer.
455 if (!Rewriter::Analyze(&info)) return Handle<SharedFunctionInfo>::null();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000456
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000457 bool is_run_once = literal->try_full_codegen();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000458 bool use_full = FLAG_full_compiler && !literal->contains_loops();
459 if (AlwaysFullCompiler() || (use_full && is_run_once)) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000460 if (!FullCodeGenerator::MakeCode(&info)) {
461 return Handle<SharedFunctionInfo>::null();
462 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000463 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000464 // We fall back to the classic V8 code generator.
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000465 AssignedVariablesAnalyzer ava;
466 if (!ava.Analyze(&info)) return Handle<SharedFunctionInfo>::null();
467 if (!CodeGenerator::MakeCode(&info)) {
468 return Handle<SharedFunctionInfo>::null();
469 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000470 }
471
472 // Function compilation complete.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000473 RecordFunctionCompilation(Logger::FUNCTION_TAG,
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000474 literal->debug_name(),
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000475 literal->start_position(),
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000476 &info);
ager@chromium.orgb5737492010-07-15 09:29:43 +0000477 scope_info = SerializedScopeInfo::Create(info.scope());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000478 }
479
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000480 // Create a shared function info object.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000481 Handle<SharedFunctionInfo> result =
482 Factory::NewSharedFunctionInfo(literal->name(),
483 literal->materialized_literal_count(),
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000484 info.code(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000485 scope_info);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000486 SetFunctionInfo(result, literal, false, script);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000487
488 // Set the expected number of properties for instances and return
489 // the resulting function.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000490 SetExpectedNofPropertiesFromEstimate(result,
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000491 literal->expected_property_count());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000492 live_edit_tracker.RecordFunctionInfo(result, literal);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000493 return result;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000494}
495
496
497// Sets the function info on a function.
498// The start_position points to the first '(' character after the function name
499// in the full script source. When counting characters in the script source the
500// the first character is number 0 (not 1).
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000501void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000502 FunctionLiteral* lit,
503 bool is_toplevel,
504 Handle<Script> script) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000505 function_info->set_length(lit->num_parameters());
506 function_info->set_formal_parameter_count(lit->num_parameters());
507 function_info->set_script(*script);
508 function_info->set_function_token_position(lit->function_token_position());
509 function_info->set_start_position(lit->start_position());
510 function_info->set_end_position(lit->end_position());
511 function_info->set_is_expression(lit->is_expression());
512 function_info->set_is_toplevel(is_toplevel);
513 function_info->set_inferred_name(*lit->inferred_name());
514 function_info->SetThisPropertyAssignmentsInfo(
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000515 lit->has_only_simple_this_property_assignments(),
516 *lit->this_property_assignments());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000517 function_info->set_try_full_codegen(lit->try_full_codegen());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000518 function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000519}
520
521
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000522void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
523 Handle<String> name,
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000524 int start_position,
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000525 CompilationInfo* info) {
526 // Log the code generation. If source information is available include
527 // script name and line number. Check explicitly whether logging is
528 // enabled as finding the line number is not free.
529 if (Logger::is_logging() ||
530 OProfileAgent::is_enabled() ||
531 CpuProfiler::is_profiling()) {
532 Handle<Script> script = info->script();
533 Handle<Code> code = info->code();
ager@chromium.org5c838252010-02-19 08:53:10 +0000534 if (script->name()->IsString()) {
535 int line_num = GetScriptLineNumber(script, start_position) + 1;
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000536 USE(line_num);
ager@chromium.org357bf652010-04-12 11:30:10 +0000537 PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000538 *code,
539 *name,
540 String::cast(script->name()),
541 line_num));
542 OPROFILE(CreateNativeCodeRegion(*name,
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000543 String::cast(script->name()),
544 line_num,
545 code->instruction_start(),
546 code->instruction_size()));
ager@chromium.org5c838252010-02-19 08:53:10 +0000547 } else {
ager@chromium.org357bf652010-04-12 11:30:10 +0000548 PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000549 *code,
550 *name));
551 OPROFILE(CreateNativeCodeRegion(*name,
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000552 code->instruction_start(),
553 code->instruction_size()));
ager@chromium.org5c838252010-02-19 08:53:10 +0000554 }
555 }
556}
ager@chromium.org5c838252010-02-19 08:53:10 +0000557
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000558} } // namespace v8::internal