blob: fe61571fa21c2e859d7eca38c0bf101e77538841 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// 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"
32#include "compilation-cache.h"
33#include "compiler.h"
34#include "debug.h"
Leon Clarke888f6722010-01-27 15:57:47 +000035#include "full-codegen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036#include "oprofile-agent.h"
37#include "rewriter.h"
38#include "scopes.h"
39#include "usage-analyzer.h"
40
41namespace v8 {
42namespace internal {
43
Steve Block3ce2e202009-11-05 08:53:23 +000044
Steve Blocka7e24c12009-10-30 11:49:00 +000045static Handle<Code> MakeCode(FunctionLiteral* literal,
46 Handle<Script> script,
47 Handle<Context> context,
Steve Blockd0582a62009-12-15 09:54:21 +000048 bool is_eval,
49 Handle<SharedFunctionInfo> shared) {
Steve Blocka7e24c12009-10-30 11:49:00 +000050 ASSERT(literal != NULL);
51
52 // Rewrite the AST by introducing .result assignments where needed.
53 if (!Rewriter::Process(literal) || !AnalyzeVariableUsage(literal)) {
54 // Signal a stack overflow by returning a null handle. The stack
55 // overflow exception will be thrown by the caller.
56 return Handle<Code>::null();
57 }
58
59 {
60 // Compute top scope and allocate variables. For lazy compilation
61 // the top scope only contains the single lazily compiled function,
62 // so this doesn't re-allocate variables repeatedly.
63 HistogramTimerScope timer(&Counters::variable_allocation);
64 Scope* top = literal->scope();
65 while (top->outer_scope() != NULL) top = top->outer_scope();
66 top->AllocateVariables(context);
67 }
68
69#ifdef DEBUG
70 if (Bootstrapper::IsActive() ?
71 FLAG_print_builtin_scopes :
72 FLAG_print_scopes) {
73 literal->scope()->Print();
74 }
75#endif
76
77 // Optimize the AST.
78 if (!Rewriter::Optimize(literal)) {
79 // Signal a stack overflow by returning a null handle. The stack
80 // overflow exception will be thrown by the caller.
81 return Handle<Code>::null();
82 }
83
84 // Generate code and return it.
Steve Block3ce2e202009-11-05 08:53:23 +000085 if (FLAG_fast_compiler) {
Steve Blockd0582a62009-12-15 09:54:21 +000086 // If there is no shared function info, try the fast code
87 // generator for code in the global scope. Otherwise obey the
88 // explicit hint in the shared function info.
89 // If always_fast_compiler is true, always try the fast compiler.
90 if (shared.is_null() && !literal->scope()->is_global_scope() &&
91 !FLAG_always_fast_compiler) {
92 if (FLAG_trace_bailout) PrintF("Non-global scope\n");
93 } else if (!shared.is_null() && !shared->try_fast_codegen() &&
94 !FLAG_always_fast_compiler) {
95 if (FLAG_trace_bailout) PrintF("No hint to try fast\n");
96 } else {
Leon Clarke888f6722010-01-27 15:57:47 +000097 FullCodeGenSyntaxChecker checker;
98 checker.Check(literal);
99 if (checker.has_supported_syntax()) {
100 return FullCodeGenerator::MakeCode(literal, script, is_eval);
Steve Blockd0582a62009-12-15 09:54:21 +0000101 }
Steve Block3ce2e202009-11-05 08:53:23 +0000102 }
Steve Block3ce2e202009-11-05 08:53:23 +0000103 }
104 return CodeGenerator::MakeCode(literal, script, is_eval);
Steve Blocka7e24c12009-10-30 11:49:00 +0000105}
106
107
108static bool IsValidJSON(FunctionLiteral* lit) {
109 if (lit->body()->length() != 1)
110 return false;
111 Statement* stmt = lit->body()->at(0);
112 if (stmt->AsExpressionStatement() == NULL)
113 return false;
114 Expression* expr = stmt->AsExpressionStatement()->expression();
115 return expr->IsValidJSON();
116}
117
118
119static Handle<JSFunction> MakeFunction(bool is_global,
120 bool is_eval,
121 Compiler::ValidationState validate,
122 Handle<Script> script,
123 Handle<Context> context,
124 v8::Extension* extension,
125 ScriptDataImpl* pre_data) {
126 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
127
128 PostponeInterruptsScope postpone;
129
130 ASSERT(!i::Top::global_context().is_null());
131 script->set_context_data((*i::Top::global_context())->data());
132
133#ifdef ENABLE_DEBUGGER_SUPPORT
134 bool is_json = (validate == Compiler::VALIDATE_JSON);
135 if (is_eval || is_json) {
136 script->set_compilation_type(
137 is_json ? Smi::FromInt(Script::COMPILATION_TYPE_JSON) :
138 Smi::FromInt(Script::COMPILATION_TYPE_EVAL));
139 // For eval scripts add information on the function from which eval was
140 // called.
141 if (is_eval) {
142 JavaScriptFrameIterator it;
Steve Blockd0582a62009-12-15 09:54:21 +0000143 script->set_eval_from_shared(
144 JSFunction::cast(it.frame()->function())->shared());
145 int offset = static_cast<int>(
146 it.frame()->pc() - it.frame()->code()->instruction_start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000147 script->set_eval_from_instructions_offset(Smi::FromInt(offset));
148 }
149 }
150
151 // Notify debugger
152 Debugger::OnBeforeCompile(script);
153#endif
154
155 // Only allow non-global compiles for eval.
156 ASSERT(is_eval || is_global);
157
158 // Build AST.
159 FunctionLiteral* lit = MakeAST(is_global, script, extension, pre_data);
160
161 // Check for parse errors.
162 if (lit == NULL) {
163 ASSERT(Top::has_pending_exception());
164 return Handle<JSFunction>::null();
165 }
166
167 // When parsing JSON we do an ordinary parse and then afterwards
168 // check the AST to ensure it was well-formed. If not we give a
169 // syntax error.
170 if (validate == Compiler::VALIDATE_JSON && !IsValidJSON(lit)) {
171 HandleScope scope;
172 Handle<JSArray> args = Factory::NewJSArray(1);
173 Handle<Object> source(script->source());
174 SetElement(args, 0, source);
175 Handle<Object> result = Factory::NewSyntaxError("invalid_json", args);
176 Top::Throw(*result, NULL);
177 return Handle<JSFunction>::null();
178 }
179
180 // Measure how long it takes to do the compilation; only take the
181 // rest of the function into account to avoid overlap with the
182 // parsing statistics.
183 HistogramTimer* rate = is_eval
184 ? &Counters::compile_eval
185 : &Counters::compile;
186 HistogramTimerScope timer(rate);
187
188 // Compile the code.
Steve Blockd0582a62009-12-15 09:54:21 +0000189 Handle<Code> code = MakeCode(lit, script, context, is_eval,
190 Handle<SharedFunctionInfo>::null());
Steve Blocka7e24c12009-10-30 11:49:00 +0000191
192 // Check for stack-overflow exceptions.
193 if (code.is_null()) {
194 Top::StackOverflow();
195 return Handle<JSFunction>::null();
196 }
197
198#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
199 // Log the code generation for the script. Check explicit whether logging is
200 // to avoid allocating when not required.
201 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
202 if (script->name()->IsString()) {
203 SmartPointer<char> data =
204 String::cast(script->name())->ToCString(DISALLOW_NULLS);
205 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
206 *code, *data));
207 OProfileAgent::CreateNativeCodeRegion(*data,
208 code->instruction_start(),
209 code->instruction_size());
210 } else {
211 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
212 *code, ""));
213 OProfileAgent::CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
214 code->instruction_start(),
215 code->instruction_size());
216 }
217 }
218#endif
219
220 // Allocate function.
221 Handle<JSFunction> fun =
222 Factory::NewFunctionBoilerplate(lit->name(),
223 lit->materialized_literal_count(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 code);
225
226 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
Steve Blockd0582a62009-12-15 09:54:21 +0000227 Compiler::SetFunctionInfo(fun, lit, true, script);
Steve Blocka7e24c12009-10-30 11:49:00 +0000228
229 // Hint to the runtime system used when allocating space for initial
230 // property space by setting the expected number of properties for
231 // the instances of the function.
232 SetExpectedNofPropertiesFromEstimate(fun, lit->expected_property_count());
233
234#ifdef ENABLE_DEBUGGER_SUPPORT
235 // Notify debugger
236 Debugger::OnAfterCompile(script, fun);
237#endif
238
239 return fun;
240}
241
242
243static StaticResource<SafeStringInputBuffer> safe_string_input_buffer;
244
245
246Handle<JSFunction> Compiler::Compile(Handle<String> source,
247 Handle<Object> script_name,
248 int line_offset, int column_offset,
249 v8::Extension* extension,
250 ScriptDataImpl* input_pre_data) {
251 int source_length = source->length();
252 Counters::total_load_size.Increment(source_length);
253 Counters::total_compile_size.Increment(source_length);
254
255 // The VM is in the COMPILER state until exiting this function.
256 VMState state(COMPILER);
257
258 // Do a lookup in the compilation cache but not for extensions.
259 Handle<JSFunction> result;
260 if (extension == NULL) {
261 result = CompilationCache::LookupScript(source,
262 script_name,
263 line_offset,
264 column_offset);
265 }
266
267 if (result.is_null()) {
268 // No cache entry found. Do pre-parsing and compile the script.
269 ScriptDataImpl* pre_data = input_pre_data;
270 if (pre_data == NULL && source_length >= FLAG_min_preparse_length) {
271 Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
272 buf->Reset(source.location());
273 pre_data = PreParse(source, buf.value(), extension);
274 }
275
276 // Create a script object describing the script to be compiled.
277 Handle<Script> script = Factory::NewScript(source);
278 if (!script_name.is_null()) {
279 script->set_name(*script_name);
280 script->set_line_offset(Smi::FromInt(line_offset));
281 script->set_column_offset(Smi::FromInt(column_offset));
282 }
283
284 // Compile the function and add it to the cache.
285 result = MakeFunction(true,
286 false,
287 DONT_VALIDATE_JSON,
288 script,
289 Handle<Context>::null(),
290 extension,
291 pre_data);
292 if (extension == NULL && !result.is_null()) {
293 CompilationCache::PutScript(source, result);
294 }
295
296 // Get rid of the pre-parsing data (if necessary).
297 if (input_pre_data == NULL && pre_data != NULL) {
298 delete pre_data;
299 }
300 }
301
302 if (result.is_null()) Top::ReportPendingMessages();
303 return result;
304}
305
306
307Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
308 Handle<Context> context,
309 bool is_global,
310 ValidationState validate) {
311 // Note that if validation is required then no path through this
312 // function is allowed to return a value without validating that
313 // the input is legal json.
314
315 int source_length = source->length();
316 Counters::total_eval_size.Increment(source_length);
317 Counters::total_compile_size.Increment(source_length);
318
319 // The VM is in the COMPILER state until exiting this function.
320 VMState state(COMPILER);
321
322 // Do a lookup in the compilation cache; if the entry is not there,
323 // invoke the compiler and add the result to the cache. If we're
324 // evaluating json we bypass the cache since we can't be sure a
325 // potential value in the cache has been validated.
326 Handle<JSFunction> result;
327 if (validate == DONT_VALIDATE_JSON)
328 result = CompilationCache::LookupEval(source, context, is_global);
329
330 if (result.is_null()) {
331 // Create a script object describing the script to be compiled.
332 Handle<Script> script = Factory::NewScript(source);
333 result = MakeFunction(is_global,
334 true,
335 validate,
336 script,
337 context,
338 NULL,
339 NULL);
340 if (!result.is_null() && validate != VALIDATE_JSON) {
341 // For json it's unlikely that we'll ever see exactly the same
342 // string again so we don't use the compilation cache.
343 CompilationCache::PutEval(source, context, is_global, result);
344 }
345 }
346
347 return result;
348}
349
350
351bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
352 int loop_nesting) {
353 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
354
355 // The VM is in the COMPILER state until exiting this function.
356 VMState state(COMPILER);
357
358 PostponeInterruptsScope postpone;
359
360 // Compute name, source code and script data.
361 Handle<String> name(String::cast(shared->name()));
362 Handle<Script> script(Script::cast(shared->script()));
363
364 int start_position = shared->start_position();
365 int end_position = shared->end_position();
366 bool is_expression = shared->is_expression();
367 Counters::total_compile_size.Increment(end_position - start_position);
368
369 // Generate the AST for the lazily compiled function. The AST may be
370 // NULL in case of parser stack overflow.
371 FunctionLiteral* lit = MakeLazyAST(script, name,
372 start_position,
373 end_position,
374 is_expression);
375
376 // Check for parse errors.
377 if (lit == NULL) {
378 ASSERT(Top::has_pending_exception());
379 return false;
380 }
381
382 // Update the loop nesting in the function literal.
383 lit->set_loop_nesting(loop_nesting);
384
385 // Measure how long it takes to do the lazy compilation; only take
386 // the rest of the function into account to avoid overlap with the
387 // lazy parsing statistics.
388 HistogramTimerScope timer(&Counters::compile_lazy);
389
390 // Compile the code.
Steve Blockd0582a62009-12-15 09:54:21 +0000391 Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false,
392 shared);
Steve Blocka7e24c12009-10-30 11:49:00 +0000393
394 // Check for stack-overflow exception.
395 if (code.is_null()) {
396 Top::StackOverflow();
397 return false;
398 }
399
400#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
401 // Log the code generation. If source information is available include script
402 // name and line number. Check explicit whether logging is enabled as finding
403 // the line number is not for free.
404 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
405 Handle<String> func_name(name->length() > 0 ?
406 *name : shared->inferred_name());
407 if (script->name()->IsString()) {
408 int line_num = GetScriptLineNumber(script, start_position) + 1;
409 LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name,
410 String::cast(script->name()), line_num));
411 OProfileAgent::CreateNativeCodeRegion(*func_name,
412 String::cast(script->name()),
413 line_num,
414 code->instruction_start(),
415 code->instruction_size());
416 } else {
417 LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name));
418 OProfileAgent::CreateNativeCodeRegion(*func_name,
419 code->instruction_start(),
420 code->instruction_size());
421 }
422 }
423#endif
424
425 // Update the shared function info with the compiled code.
426 shared->set_code(*code);
427
428 // Set the expected number of properties for instances.
429 SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
430
431 // Set the optimication hints after performing lazy compilation, as these are
432 // not set when the function is set up as a lazily compiled function.
433 shared->SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +0000434 lit->has_only_simple_this_property_assignments(),
435 *lit->this_property_assignments());
436
437 // Check the function has compiled code.
438 ASSERT(shared->is_compiled());
439 return true;
440}
441
442
Steve Blockd0582a62009-12-15 09:54:21 +0000443Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
444 Handle<Script> script,
445 AstVisitor* caller) {
446#ifdef DEBUG
447 // We should not try to compile the same function literal more than
448 // once.
449 literal->mark_as_compiled();
450#endif
451
452 // Determine if the function can be lazily compiled. This is
453 // necessary to allow some of our builtin JS files to be lazily
454 // compiled. These builtins cannot be handled lazily by the parser,
455 // since we have to know if a function uses the special natives
456 // syntax, which is something the parser records.
457 bool allow_lazy = literal->AllowsLazyCompilation();
458
459 // Generate code
460 Handle<Code> code;
461 if (FLAG_lazy && allow_lazy) {
462 code = ComputeLazyCompile(literal->num_parameters());
463 } else {
464 // The bodies of function literals have not yet been visited by
465 // the AST optimizer/analyzer.
466 if (!Rewriter::Optimize(literal)) {
467 return Handle<JSFunction>::null();
468 }
469
470 // Generate code and return it.
471 bool is_compiled = false;
Leon Clarke888f6722010-01-27 15:57:47 +0000472 if (FLAG_always_fast_compiler ||
473 (FLAG_fast_compiler && literal->try_fast_codegen())) {
474 FullCodeGenSyntaxChecker checker;
475 checker.Check(literal);
476 if (checker.has_supported_syntax()) {
477 code = FullCodeGenerator::MakeCode(literal,
Steve Blockd0582a62009-12-15 09:54:21 +0000478 script,
479 false); // Not eval.
480 is_compiled = true;
481 }
482 }
483
484 if (!is_compiled) {
485 // We didn't try the fast compiler, or we failed to select it.
486 code = CodeGenerator::MakeCode(literal,
487 script,
488 false); // Not eval.
489 }
490
491 // Check for stack-overflow exception.
492 if (code.is_null()) {
493 caller->SetStackOverflow();
494 return Handle<JSFunction>::null();
495 }
496
497 // Function compilation complete.
498 LOG(CodeCreateEvent(Logger::FUNCTION_TAG, *code, *literal->name()));
499
500#ifdef ENABLE_OPROFILE_AGENT
Leon Clarkee46be812010-01-19 14:06:41 +0000501 OProfileAgent::CreateNativeCodeRegion(*literal->name(),
Steve Blockd0582a62009-12-15 09:54:21 +0000502 code->instruction_start(),
503 code->instruction_size());
504#endif
505 }
506
507 // Create a boilerplate function.
508 Handle<JSFunction> function =
509 Factory::NewFunctionBoilerplate(literal->name(),
510 literal->materialized_literal_count(),
511 code);
512 SetFunctionInfo(function, literal, false, script);
513
514#ifdef ENABLE_DEBUGGER_SUPPORT
515 // Notify debugger that a new function has been added.
516 Debugger::OnNewFunction(function);
517#endif
518
519 // Set the expected number of properties for instances and return
520 // the resulting function.
521 SetExpectedNofPropertiesFromEstimate(function,
522 literal->expected_property_count());
523 return function;
524}
525
526
527// Sets the function info on a function.
528// The start_position points to the first '(' character after the function name
529// in the full script source. When counting characters in the script source the
530// the first character is number 0 (not 1).
531void Compiler::SetFunctionInfo(Handle<JSFunction> fun,
532 FunctionLiteral* lit,
533 bool is_toplevel,
534 Handle<Script> script) {
535 fun->shared()->set_length(lit->num_parameters());
536 fun->shared()->set_formal_parameter_count(lit->num_parameters());
537 fun->shared()->set_script(*script);
538 fun->shared()->set_function_token_position(lit->function_token_position());
539 fun->shared()->set_start_position(lit->start_position());
540 fun->shared()->set_end_position(lit->end_position());
541 fun->shared()->set_is_expression(lit->is_expression());
542 fun->shared()->set_is_toplevel(is_toplevel);
543 fun->shared()->set_inferred_name(*lit->inferred_name());
544 fun->shared()->SetThisPropertyAssignmentsInfo(
545 lit->has_only_simple_this_property_assignments(),
546 *lit->this_property_assignments());
547 fun->shared()->set_try_fast_codegen(lit->try_fast_codegen());
548}
549
550
Steve Blocka7e24c12009-10-30 11:49:00 +0000551} } // namespace v8::internal