blob: 11098bae98e160e5a107b03270ab745ae68c3d7f [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,
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000281 Handle<Object> script_data,
282 NativesFlag natives) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000283 int source_length = source->length();
284 Counters::total_load_size.Increment(source_length);
285 Counters::total_compile_size.Increment(source_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000286
287 // The VM is in the COMPILER state until exiting this function.
288 VMState state(COMPILER);
289
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000290 // Do a lookup in the compilation cache but not for extensions.
291 Handle<JSFunction> result;
292 if (extension == NULL) {
293 result = CompilationCache::LookupScript(source,
294 script_name,
295 line_offset,
296 column_offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297 }
298
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000299 if (result.is_null()) {
300 // No cache entry found. Do pre-parsing and compile the script.
301 ScriptDataImpl* pre_data = input_pre_data;
ager@chromium.org870a0b62008-11-04 11:43:05 +0000302 if (pre_data == NULL && source_length >= FLAG_min_preparse_length) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000303 Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
304 buf->Reset(source.location());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000305 pre_data = PreParse(source, buf.value(), extension);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000306 }
307
308 // Create a script object describing the script to be compiled.
309 Handle<Script> script = Factory::NewScript(source);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000310 if (natives == NATIVES_CODE) {
311 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
312 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000313 if (!script_name.is_null()) {
314 script->set_name(*script_name);
315 script->set_line_offset(Smi::FromInt(line_offset));
316 script->set_column_offset(Smi::FromInt(column_offset));
317 }
318
ager@chromium.org5c838252010-02-19 08:53:10 +0000319 script->set_data(script_data.is_null() ? Heap::undefined_value()
320 : *script_data);
321
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000322 // Compile the function and add it to the cache.
ager@chromium.org381abbb2009-02-25 13:23:22 +0000323 result = MakeFunction(true,
324 false,
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000325 DONT_VALIDATE_JSON,
ager@chromium.org381abbb2009-02-25 13:23:22 +0000326 script,
327 Handle<Context>::null(),
328 extension,
329 pre_data);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000330 if (extension == NULL && !result.is_null()) {
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +0000331 CompilationCache::PutScript(source, result);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000332 }
333
334 // Get rid of the pre-parsing data (if necessary).
335 if (input_pre_data == NULL && pre_data != NULL) {
336 delete pre_data;
337 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338 }
339
ager@chromium.org8bb60582008-12-11 12:02:20 +0000340 if (result.is_null()) Top::ReportPendingMessages();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341 return result;
342}
343
344
ager@chromium.org236ad962008-09-25 09:45:57 +0000345Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
ager@chromium.org381abbb2009-02-25 13:23:22 +0000346 Handle<Context> context,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000347 bool is_global,
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000348 ValidationState validate) {
349 // Note that if validation is required then no path through this
350 // function is allowed to return a value without validating that
351 // the input is legal json.
352
ager@chromium.orgc3e50d82008-11-05 11:53:10 +0000353 int source_length = source->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000354 Counters::total_eval_size.Increment(source_length);
355 Counters::total_compile_size.Increment(source_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000356
357 // The VM is in the COMPILER state until exiting this function.
358 VMState state(COMPILER);
359
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000360 // Do a lookup in the compilation cache; if the entry is not there,
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000361 // invoke the compiler and add the result to the cache. If we're
362 // evaluating json we bypass the cache since we can't be sure a
363 // potential value in the cache has been validated.
364 Handle<JSFunction> result;
365 if (validate == DONT_VALIDATE_JSON)
366 result = CompilationCache::LookupEval(source, context, is_global);
367
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000368 if (result.is_null()) {
369 // Create a script object describing the script to be compiled.
370 Handle<Script> script = Factory::NewScript(source);
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000371 result = MakeFunction(is_global,
372 true,
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000373 validate,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000374 script,
375 context,
376 NULL,
377 NULL);
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000378 if (!result.is_null() && validate != VALIDATE_JSON) {
379 // For json it's unlikely that we'll ever see exactly the same
380 // string again so we don't use the compilation cache.
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000381 CompilationCache::PutEval(source, context, is_global, result);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000382 }
383 }
ager@chromium.org8bb60582008-12-11 12:02:20 +0000384
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000385 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386}
387
388
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000389bool Compiler::CompileLazy(CompilationInfo* info) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000390 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391
392 // The VM is in the COMPILER state until exiting this function.
393 VMState state(COMPILER);
394
kasper.lund44510672008-07-25 07:37:58 +0000395 PostponeInterruptsScope postpone;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396
397 // Compute name, source code and script data.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000398 Handle<SharedFunctionInfo> shared = info->shared_info();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 Handle<String> name(String::cast(shared->name()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400
401 int start_position = shared->start_position();
402 int end_position = shared->end_position();
403 bool is_expression = shared->is_expression();
404 Counters::total_compile_size.Increment(end_position - start_position);
405
406 // Generate the AST for the lazily compiled function. The AST may be
407 // NULL in case of parser stack overflow.
ager@chromium.org5c838252010-02-19 08:53:10 +0000408 FunctionLiteral* lit = MakeLazyAST(info->script(),
409 name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 start_position,
411 end_position,
412 is_expression);
413
kasper.lund212ac232008-07-16 07:07:30 +0000414 // Check for parse errors.
415 if (lit == NULL) {
416 ASSERT(Top::has_pending_exception());
kasper.lund212ac232008-07-16 07:07:30 +0000417 return false;
418 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000419 info->set_function(lit);
kasper.lund212ac232008-07-16 07:07:30 +0000420
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000421 // Measure how long it takes to do the lazy compilation; only take
422 // the rest of the function into account to avoid overlap with the
423 // lazy parsing statistics.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000424 HistogramTimerScope timer(&Counters::compile_lazy);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000425
kasper.lund212ac232008-07-16 07:07:30 +0000426 // Compile the code.
ager@chromium.org5c838252010-02-19 08:53:10 +0000427 Handle<Code> code = MakeCode(Handle<Context>::null(), info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428
kasper.lund212ac232008-07-16 07:07:30 +0000429 // Check for stack-overflow exception.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000430 if (code.is_null()) {
kasper.lund212ac232008-07-16 07:07:30 +0000431 Top::StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 return false;
433 }
434
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000435#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
ager@chromium.org5c838252010-02-19 08:53:10 +0000436 LogCodeCreateEvent(Logger::LAZY_COMPILE_TAG,
437 name,
438 Handle<String>(shared->inferred_name()),
439 start_position,
440 info->script(),
441 code);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000442#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000443
444 // Update the shared function info with the compiled code.
445 shared->set_code(*code);
446
447 // Set the expected number of properties for instances.
448 SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
449
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000450 // Set the optimication hints after performing lazy compilation, as these are
451 // not set when the function is set up as a lazily compiled function.
452 shared->SetThisPropertyAssignmentsInfo(
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000453 lit->has_only_simple_this_property_assignments(),
454 *lit->this_property_assignments());
455
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456 // Check the function has compiled code.
457 ASSERT(shared->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000458 return true;
459}
460
461
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000462Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
463 Handle<Script> script,
464 AstVisitor* caller) {
465#ifdef DEBUG
466 // We should not try to compile the same function literal more than
467 // once.
468 literal->mark_as_compiled();
469#endif
470
471 // Determine if the function can be lazily compiled. This is
472 // necessary to allow some of our builtin JS files to be lazily
473 // compiled. These builtins cannot be handled lazily by the parser,
474 // since we have to know if a function uses the special natives
475 // syntax, which is something the parser records.
ager@chromium.org5c838252010-02-19 08:53:10 +0000476 bool allow_lazy = literal->AllowsLazyCompilation() &&
477 !LiveEditFunctionTracker::IsActive();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000478
479 // Generate code
480 Handle<Code> code;
481 if (FLAG_lazy && allow_lazy) {
482 code = ComputeLazyCompile(literal->num_parameters());
483 } else {
484 // The bodies of function literals have not yet been visited by
485 // the AST optimizer/analyzer.
486 if (!Rewriter::Optimize(literal)) {
487 return Handle<JSFunction>::null();
488 }
489
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000490 if (literal->scope()->num_parameters() > 0 ||
491 literal->scope()->num_stack_slots()) {
492 AssignedVariablesAnalyzer ava(literal);
493 ava.Analyze();
494 if (ava.HasStackOverflow()) {
495 return Handle<JSFunction>::null();
496 }
497 }
498
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000499 if (FLAG_use_flow_graph) {
500 FlowGraphBuilder builder;
501 builder.Build(literal);
502
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000503 if (!builder.HasStackOverflow()) {
504 int variable_count =
505 literal->num_parameters() + literal->scope()->num_stack_slots();
506 if (variable_count > 0 && builder.definitions()->length() > 0) {
507 ReachingDefinitions rd(builder.postorder(),
508 builder.definitions(),
509 variable_count);
510 rd.Compute();
511 }
512 }
513
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000514#ifdef DEBUG
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000515 if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000516 builder.graph()->PrintText(builder.postorder());
517 }
518#endif
519 }
520
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000521 // Generate code and return it. The way that the compilation mode
522 // is controlled by the command-line flags is described in
523 // the static helper function MakeCode.
ager@chromium.org5c838252010-02-19 08:53:10 +0000524 CompilationInfo info(literal, script, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000525
526 CHECK(!FLAG_always_full_compiler || !FLAG_always_fast_compiler);
527 bool is_run_once = literal->try_full_codegen();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000528 bool is_compiled = false;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000529 if (FLAG_always_full_compiler || (FLAG_full_compiler && is_run_once)) {
530 FullCodeGenSyntaxChecker checker;
531 checker.Check(literal);
532 if (checker.has_supported_syntax()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000533 code = FullCodeGenerator::MakeCode(&info);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000534 is_compiled = true;
535 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000536 } else if (FLAG_always_fast_compiler ||
537 (FLAG_fast_compiler && !is_run_once)) {
538 // Since we are not lazily compiling we do not have a receiver to
539 // specialize for.
540 FastCodeGenSyntaxChecker checker;
ager@chromium.org5c838252010-02-19 08:53:10 +0000541 checker.Check(&info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000542 if (checker.has_supported_syntax()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000543 code = FastCodeGenerator::MakeCode(&info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000544 is_compiled = true;
545 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000546 }
547
548 if (!is_compiled) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000549 // We fall back to the classic V8 code generator.
ager@chromium.org5c838252010-02-19 08:53:10 +0000550 code = CodeGenerator::MakeCode(&info);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000551 }
552
553 // Check for stack-overflow exception.
554 if (code.is_null()) {
555 caller->SetStackOverflow();
556 return Handle<JSFunction>::null();
557 }
558
559 // Function compilation complete.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000560
ager@chromium.org5c838252010-02-19 08:53:10 +0000561#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
562 LogCodeCreateEvent(Logger::FUNCTION_TAG,
563 literal->name(),
564 literal->inferred_name(),
565 literal->start_position(),
566 script,
567 code);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000568#endif
569 }
570
571 // Create a boilerplate function.
572 Handle<JSFunction> function =
573 Factory::NewFunctionBoilerplate(literal->name(),
574 literal->materialized_literal_count(),
575 code);
576 SetFunctionInfo(function, literal, false, script);
577
578#ifdef ENABLE_DEBUGGER_SUPPORT
579 // Notify debugger that a new function has been added.
580 Debugger::OnNewFunction(function);
581#endif
582
583 // Set the expected number of properties for instances and return
584 // the resulting function.
585 SetExpectedNofPropertiesFromEstimate(function,
586 literal->expected_property_count());
587 return function;
588}
589
590
591// Sets the function info on a function.
592// The start_position points to the first '(' character after the function name
593// in the full script source. When counting characters in the script source the
594// the first character is number 0 (not 1).
595void Compiler::SetFunctionInfo(Handle<JSFunction> fun,
596 FunctionLiteral* lit,
597 bool is_toplevel,
598 Handle<Script> script) {
599 fun->shared()->set_length(lit->num_parameters());
600 fun->shared()->set_formal_parameter_count(lit->num_parameters());
601 fun->shared()->set_script(*script);
602 fun->shared()->set_function_token_position(lit->function_token_position());
603 fun->shared()->set_start_position(lit->start_position());
604 fun->shared()->set_end_position(lit->end_position());
605 fun->shared()->set_is_expression(lit->is_expression());
606 fun->shared()->set_is_toplevel(is_toplevel);
607 fun->shared()->set_inferred_name(*lit->inferred_name());
608 fun->shared()->SetThisPropertyAssignmentsInfo(
609 lit->has_only_simple_this_property_assignments(),
610 *lit->this_property_assignments());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000611 fun->shared()->set_try_full_codegen(lit->try_full_codegen());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000612}
613
614
ager@chromium.org5c838252010-02-19 08:53:10 +0000615#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
616void Compiler::LogCodeCreateEvent(Logger::LogEventsAndTags tag,
617 Handle<String> name,
618 Handle<String> inferred_name,
619 int start_position,
620 Handle<Script> script,
621 Handle<Code> code) {
622 // Log the code generation. If source information is available
623 // include script name and line number. Check explicitly whether
624 // logging is enabled as finding the line number is not free.
625 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
626 Handle<String> func_name(name->length() > 0 ? *name : *inferred_name);
627 if (script->name()->IsString()) {
628 int line_num = GetScriptLineNumber(script, start_position) + 1;
629 LOG(CodeCreateEvent(tag, *code, *func_name,
630 String::cast(script->name()), line_num));
631 OProfileAgent::CreateNativeCodeRegion(*func_name,
632 String::cast(script->name()),
633 line_num,
634 code->instruction_start(),
635 code->instruction_size());
636 } else {
637 LOG(CodeCreateEvent(tag, *code, *func_name));
638 OProfileAgent::CreateNativeCodeRegion(*func_name,
639 code->instruction_start(),
640 code->instruction_size());
641 }
642 }
643}
644#endif
645
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646} } // namespace v8::internal