blob: 48da63dfdb9a088fa8a3c33721c35023f7e93098 [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"
Steve Block3ce2e202009-11-05 08:53:23 +000035#include "fast-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
45class CodeGenSelector: public AstVisitor {
46 public:
47 enum CodeGenTag { NORMAL, FAST };
48
Steve Blockd0582a62009-12-15 09:54:21 +000049 CodeGenSelector()
50 : has_supported_syntax_(true),
51 context_(Expression::kUninitialized) {
52 }
Steve Block3ce2e202009-11-05 08:53:23 +000053
54 CodeGenTag Select(FunctionLiteral* fun);
55
56 private:
Steve Blockd0582a62009-12-15 09:54:21 +000057 // Visit an expression in a given expression context.
58 void ProcessExpression(Expression* expr, Expression::Context context) {
59 Expression::Context saved = context_;
60 context_ = context;
61 Visit(expr);
62 expr->set_context(context);
63 context_ = saved;
64 }
65
Steve Block3ce2e202009-11-05 08:53:23 +000066 void VisitDeclarations(ZoneList<Declaration*>* decls);
67 void VisitStatements(ZoneList<Statement*>* stmts);
68
69 // AST node visit functions.
70#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
71 AST_NODE_LIST(DECLARE_VISIT)
72#undef DECLARE_VISIT
73
74 bool has_supported_syntax_;
75
Steve Blockd0582a62009-12-15 09:54:21 +000076 // The desired expression context of the currently visited expression.
77 Expression::Context context_;
78
Steve Block3ce2e202009-11-05 08:53:23 +000079 DISALLOW_COPY_AND_ASSIGN(CodeGenSelector);
80};
81
82
Steve Blocka7e24c12009-10-30 11:49:00 +000083static Handle<Code> MakeCode(FunctionLiteral* literal,
84 Handle<Script> script,
85 Handle<Context> context,
Steve Blockd0582a62009-12-15 09:54:21 +000086 bool is_eval,
87 Handle<SharedFunctionInfo> shared) {
Steve Blocka7e24c12009-10-30 11:49:00 +000088 ASSERT(literal != NULL);
89
90 // Rewrite the AST by introducing .result assignments where needed.
91 if (!Rewriter::Process(literal) || !AnalyzeVariableUsage(literal)) {
92 // Signal a stack overflow by returning a null handle. The stack
93 // overflow exception will be thrown by the caller.
94 return Handle<Code>::null();
95 }
96
97 {
98 // Compute top scope and allocate variables. For lazy compilation
99 // the top scope only contains the single lazily compiled function,
100 // so this doesn't re-allocate variables repeatedly.
101 HistogramTimerScope timer(&Counters::variable_allocation);
102 Scope* top = literal->scope();
103 while (top->outer_scope() != NULL) top = top->outer_scope();
104 top->AllocateVariables(context);
105 }
106
107#ifdef DEBUG
108 if (Bootstrapper::IsActive() ?
109 FLAG_print_builtin_scopes :
110 FLAG_print_scopes) {
111 literal->scope()->Print();
112 }
113#endif
114
115 // Optimize the AST.
116 if (!Rewriter::Optimize(literal)) {
117 // Signal a stack overflow by returning a null handle. The stack
118 // overflow exception will be thrown by the caller.
119 return Handle<Code>::null();
120 }
121
122 // Generate code and return it.
Steve Block3ce2e202009-11-05 08:53:23 +0000123 if (FLAG_fast_compiler) {
Steve Blockd0582a62009-12-15 09:54:21 +0000124 // If there is no shared function info, try the fast code
125 // generator for code in the global scope. Otherwise obey the
126 // explicit hint in the shared function info.
127 // If always_fast_compiler is true, always try the fast compiler.
128 if (shared.is_null() && !literal->scope()->is_global_scope() &&
129 !FLAG_always_fast_compiler) {
130 if (FLAG_trace_bailout) PrintF("Non-global scope\n");
131 } else if (!shared.is_null() && !shared->try_fast_codegen() &&
132 !FLAG_always_fast_compiler) {
133 if (FLAG_trace_bailout) PrintF("No hint to try fast\n");
134 } else {
135 CodeGenSelector selector;
136 CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
137 if (code_gen == CodeGenSelector::FAST) {
138 return FastCodeGenerator::MakeCode(literal, script, is_eval);
139 }
140 ASSERT(code_gen == CodeGenSelector::NORMAL);
Steve Block3ce2e202009-11-05 08:53:23 +0000141 }
Steve Block3ce2e202009-11-05 08:53:23 +0000142 }
143 return CodeGenerator::MakeCode(literal, script, is_eval);
Steve Blocka7e24c12009-10-30 11:49:00 +0000144}
145
146
147static bool IsValidJSON(FunctionLiteral* lit) {
148 if (lit->body()->length() != 1)
149 return false;
150 Statement* stmt = lit->body()->at(0);
151 if (stmt->AsExpressionStatement() == NULL)
152 return false;
153 Expression* expr = stmt->AsExpressionStatement()->expression();
154 return expr->IsValidJSON();
155}
156
157
158static Handle<JSFunction> MakeFunction(bool is_global,
159 bool is_eval,
160 Compiler::ValidationState validate,
161 Handle<Script> script,
162 Handle<Context> context,
163 v8::Extension* extension,
164 ScriptDataImpl* pre_data) {
165 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
166
167 PostponeInterruptsScope postpone;
168
169 ASSERT(!i::Top::global_context().is_null());
170 script->set_context_data((*i::Top::global_context())->data());
171
172#ifdef ENABLE_DEBUGGER_SUPPORT
173 bool is_json = (validate == Compiler::VALIDATE_JSON);
174 if (is_eval || is_json) {
175 script->set_compilation_type(
176 is_json ? Smi::FromInt(Script::COMPILATION_TYPE_JSON) :
177 Smi::FromInt(Script::COMPILATION_TYPE_EVAL));
178 // For eval scripts add information on the function from which eval was
179 // called.
180 if (is_eval) {
181 JavaScriptFrameIterator it;
Steve Blockd0582a62009-12-15 09:54:21 +0000182 script->set_eval_from_shared(
183 JSFunction::cast(it.frame()->function())->shared());
184 int offset = static_cast<int>(
185 it.frame()->pc() - it.frame()->code()->instruction_start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000186 script->set_eval_from_instructions_offset(Smi::FromInt(offset));
187 }
188 }
189
190 // Notify debugger
191 Debugger::OnBeforeCompile(script);
192#endif
193
194 // Only allow non-global compiles for eval.
195 ASSERT(is_eval || is_global);
196
197 // Build AST.
198 FunctionLiteral* lit = MakeAST(is_global, script, extension, pre_data);
199
200 // Check for parse errors.
201 if (lit == NULL) {
202 ASSERT(Top::has_pending_exception());
203 return Handle<JSFunction>::null();
204 }
205
206 // When parsing JSON we do an ordinary parse and then afterwards
207 // check the AST to ensure it was well-formed. If not we give a
208 // syntax error.
209 if (validate == Compiler::VALIDATE_JSON && !IsValidJSON(lit)) {
210 HandleScope scope;
211 Handle<JSArray> args = Factory::NewJSArray(1);
212 Handle<Object> source(script->source());
213 SetElement(args, 0, source);
214 Handle<Object> result = Factory::NewSyntaxError("invalid_json", args);
215 Top::Throw(*result, NULL);
216 return Handle<JSFunction>::null();
217 }
218
219 // Measure how long it takes to do the compilation; only take the
220 // rest of the function into account to avoid overlap with the
221 // parsing statistics.
222 HistogramTimer* rate = is_eval
223 ? &Counters::compile_eval
224 : &Counters::compile;
225 HistogramTimerScope timer(rate);
226
227 // Compile the code.
Steve Blockd0582a62009-12-15 09:54:21 +0000228 Handle<Code> code = MakeCode(lit, script, context, is_eval,
229 Handle<SharedFunctionInfo>::null());
Steve Blocka7e24c12009-10-30 11:49:00 +0000230
231 // Check for stack-overflow exceptions.
232 if (code.is_null()) {
233 Top::StackOverflow();
234 return Handle<JSFunction>::null();
235 }
236
237#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
238 // Log the code generation for the script. Check explicit whether logging is
239 // to avoid allocating when not required.
240 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
241 if (script->name()->IsString()) {
242 SmartPointer<char> data =
243 String::cast(script->name())->ToCString(DISALLOW_NULLS);
244 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
245 *code, *data));
246 OProfileAgent::CreateNativeCodeRegion(*data,
247 code->instruction_start(),
248 code->instruction_size());
249 } else {
250 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
251 *code, ""));
252 OProfileAgent::CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
253 code->instruction_start(),
254 code->instruction_size());
255 }
256 }
257#endif
258
259 // Allocate function.
260 Handle<JSFunction> fun =
261 Factory::NewFunctionBoilerplate(lit->name(),
262 lit->materialized_literal_count(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000263 code);
264
265 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
Steve Blockd0582a62009-12-15 09:54:21 +0000266 Compiler::SetFunctionInfo(fun, lit, true, script);
Steve Blocka7e24c12009-10-30 11:49:00 +0000267
268 // Hint to the runtime system used when allocating space for initial
269 // property space by setting the expected number of properties for
270 // the instances of the function.
271 SetExpectedNofPropertiesFromEstimate(fun, lit->expected_property_count());
272
273#ifdef ENABLE_DEBUGGER_SUPPORT
274 // Notify debugger
275 Debugger::OnAfterCompile(script, fun);
276#endif
277
278 return fun;
279}
280
281
282static StaticResource<SafeStringInputBuffer> safe_string_input_buffer;
283
284
285Handle<JSFunction> Compiler::Compile(Handle<String> source,
286 Handle<Object> script_name,
287 int line_offset, int column_offset,
288 v8::Extension* extension,
289 ScriptDataImpl* input_pre_data) {
290 int source_length = source->length();
291 Counters::total_load_size.Increment(source_length);
292 Counters::total_compile_size.Increment(source_length);
293
294 // The VM is in the COMPILER state until exiting this function.
295 VMState state(COMPILER);
296
297 // Do a lookup in the compilation cache but not for extensions.
298 Handle<JSFunction> result;
299 if (extension == NULL) {
300 result = CompilationCache::LookupScript(source,
301 script_name,
302 line_offset,
303 column_offset);
304 }
305
306 if (result.is_null()) {
307 // No cache entry found. Do pre-parsing and compile the script.
308 ScriptDataImpl* pre_data = input_pre_data;
309 if (pre_data == NULL && source_length >= FLAG_min_preparse_length) {
310 Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
311 buf->Reset(source.location());
312 pre_data = PreParse(source, buf.value(), extension);
313 }
314
315 // Create a script object describing the script to be compiled.
316 Handle<Script> script = Factory::NewScript(source);
317 if (!script_name.is_null()) {
318 script->set_name(*script_name);
319 script->set_line_offset(Smi::FromInt(line_offset));
320 script->set_column_offset(Smi::FromInt(column_offset));
321 }
322
323 // Compile the function and add it to the cache.
324 result = MakeFunction(true,
325 false,
326 DONT_VALIDATE_JSON,
327 script,
328 Handle<Context>::null(),
329 extension,
330 pre_data);
331 if (extension == NULL && !result.is_null()) {
332 CompilationCache::PutScript(source, result);
333 }
334
335 // Get rid of the pre-parsing data (if necessary).
336 if (input_pre_data == NULL && pre_data != NULL) {
337 delete pre_data;
338 }
339 }
340
341 if (result.is_null()) Top::ReportPendingMessages();
342 return result;
343}
344
345
346Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
347 Handle<Context> context,
348 bool is_global,
349 ValidationState validate) {
350 // Note that if validation is required then no path through this
351 // function is allowed to return a value without validating that
352 // the input is legal json.
353
354 int source_length = source->length();
355 Counters::total_eval_size.Increment(source_length);
356 Counters::total_compile_size.Increment(source_length);
357
358 // The VM is in the COMPILER state until exiting this function.
359 VMState state(COMPILER);
360
361 // Do a lookup in the compilation cache; if the entry is not there,
362 // invoke the compiler and add the result to the cache. If we're
363 // evaluating json we bypass the cache since we can't be sure a
364 // potential value in the cache has been validated.
365 Handle<JSFunction> result;
366 if (validate == DONT_VALIDATE_JSON)
367 result = CompilationCache::LookupEval(source, context, is_global);
368
369 if (result.is_null()) {
370 // Create a script object describing the script to be compiled.
371 Handle<Script> script = Factory::NewScript(source);
372 result = MakeFunction(is_global,
373 true,
374 validate,
375 script,
376 context,
377 NULL,
378 NULL);
379 if (!result.is_null() && validate != VALIDATE_JSON) {
380 // For json it's unlikely that we'll ever see exactly the same
381 // string again so we don't use the compilation cache.
382 CompilationCache::PutEval(source, context, is_global, result);
383 }
384 }
385
386 return result;
387}
388
389
390bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
391 int loop_nesting) {
392 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
393
394 // The VM is in the COMPILER state until exiting this function.
395 VMState state(COMPILER);
396
397 PostponeInterruptsScope postpone;
398
399 // Compute name, source code and script data.
400 Handle<String> name(String::cast(shared->name()));
401 Handle<Script> script(Script::cast(shared->script()));
402
403 int start_position = shared->start_position();
404 int end_position = shared->end_position();
405 bool is_expression = shared->is_expression();
406 Counters::total_compile_size.Increment(end_position - start_position);
407
408 // Generate the AST for the lazily compiled function. The AST may be
409 // NULL in case of parser stack overflow.
410 FunctionLiteral* lit = MakeLazyAST(script, name,
411 start_position,
412 end_position,
413 is_expression);
414
415 // Check for parse errors.
416 if (lit == NULL) {
417 ASSERT(Top::has_pending_exception());
418 return false;
419 }
420
421 // Update the loop nesting in the function literal.
422 lit->set_loop_nesting(loop_nesting);
423
424 // Measure how long it takes to do the lazy compilation; only take
425 // the rest of the function into account to avoid overlap with the
426 // lazy parsing statistics.
427 HistogramTimerScope timer(&Counters::compile_lazy);
428
429 // Compile the code.
Steve Blockd0582a62009-12-15 09:54:21 +0000430 Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false,
431 shared);
Steve Blocka7e24c12009-10-30 11:49:00 +0000432
433 // Check for stack-overflow exception.
434 if (code.is_null()) {
435 Top::StackOverflow();
436 return false;
437 }
438
439#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
440 // Log the code generation. If source information is available include script
441 // name and line number. Check explicit whether logging is enabled as finding
442 // the line number is not for free.
443 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
444 Handle<String> func_name(name->length() > 0 ?
445 *name : shared->inferred_name());
446 if (script->name()->IsString()) {
447 int line_num = GetScriptLineNumber(script, start_position) + 1;
448 LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name,
449 String::cast(script->name()), line_num));
450 OProfileAgent::CreateNativeCodeRegion(*func_name,
451 String::cast(script->name()),
452 line_num,
453 code->instruction_start(),
454 code->instruction_size());
455 } else {
456 LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name));
457 OProfileAgent::CreateNativeCodeRegion(*func_name,
458 code->instruction_start(),
459 code->instruction_size());
460 }
461 }
462#endif
463
464 // Update the shared function info with the compiled code.
465 shared->set_code(*code);
466
467 // Set the expected number of properties for instances.
468 SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
469
470 // Set the optimication hints after performing lazy compilation, as these are
471 // not set when the function is set up as a lazily compiled function.
472 shared->SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +0000473 lit->has_only_simple_this_property_assignments(),
474 *lit->this_property_assignments());
475
476 // Check the function has compiled code.
477 ASSERT(shared->is_compiled());
478 return true;
479}
480
481
Steve Blockd0582a62009-12-15 09:54:21 +0000482Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
483 Handle<Script> script,
484 AstVisitor* caller) {
485#ifdef DEBUG
486 // We should not try to compile the same function literal more than
487 // once.
488 literal->mark_as_compiled();
489#endif
490
491 // Determine if the function can be lazily compiled. This is
492 // necessary to allow some of our builtin JS files to be lazily
493 // compiled. These builtins cannot be handled lazily by the parser,
494 // since we have to know if a function uses the special natives
495 // syntax, which is something the parser records.
496 bool allow_lazy = literal->AllowsLazyCompilation();
497
498 // Generate code
499 Handle<Code> code;
500 if (FLAG_lazy && allow_lazy) {
501 code = ComputeLazyCompile(literal->num_parameters());
502 } else {
503 // The bodies of function literals have not yet been visited by
504 // the AST optimizer/analyzer.
505 if (!Rewriter::Optimize(literal)) {
506 return Handle<JSFunction>::null();
507 }
508
509 // Generate code and return it.
510 bool is_compiled = false;
511 if (FLAG_fast_compiler && literal->try_fast_codegen()) {
512 CodeGenSelector selector;
513 CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
514 if (code_gen == CodeGenSelector::FAST) {
515 code = FastCodeGenerator::MakeCode(literal,
516 script,
517 false); // Not eval.
518 is_compiled = true;
519 }
520 }
521
522 if (!is_compiled) {
523 // We didn't try the fast compiler, or we failed to select it.
524 code = CodeGenerator::MakeCode(literal,
525 script,
526 false); // Not eval.
527 }
528
529 // Check for stack-overflow exception.
530 if (code.is_null()) {
531 caller->SetStackOverflow();
532 return Handle<JSFunction>::null();
533 }
534
535 // Function compilation complete.
536 LOG(CodeCreateEvent(Logger::FUNCTION_TAG, *code, *literal->name()));
537
538#ifdef ENABLE_OPROFILE_AGENT
539 OProfileAgent::CreateNativeCodeRegion(*node->name(),
540 code->instruction_start(),
541 code->instruction_size());
542#endif
543 }
544
545 // Create a boilerplate function.
546 Handle<JSFunction> function =
547 Factory::NewFunctionBoilerplate(literal->name(),
548 literal->materialized_literal_count(),
549 code);
550 SetFunctionInfo(function, literal, false, script);
551
552#ifdef ENABLE_DEBUGGER_SUPPORT
553 // Notify debugger that a new function has been added.
554 Debugger::OnNewFunction(function);
555#endif
556
557 // Set the expected number of properties for instances and return
558 // the resulting function.
559 SetExpectedNofPropertiesFromEstimate(function,
560 literal->expected_property_count());
561 return function;
562}
563
564
565// Sets the function info on a function.
566// The start_position points to the first '(' character after the function name
567// in the full script source. When counting characters in the script source the
568// the first character is number 0 (not 1).
569void Compiler::SetFunctionInfo(Handle<JSFunction> fun,
570 FunctionLiteral* lit,
571 bool is_toplevel,
572 Handle<Script> script) {
573 fun->shared()->set_length(lit->num_parameters());
574 fun->shared()->set_formal_parameter_count(lit->num_parameters());
575 fun->shared()->set_script(*script);
576 fun->shared()->set_function_token_position(lit->function_token_position());
577 fun->shared()->set_start_position(lit->start_position());
578 fun->shared()->set_end_position(lit->end_position());
579 fun->shared()->set_is_expression(lit->is_expression());
580 fun->shared()->set_is_toplevel(is_toplevel);
581 fun->shared()->set_inferred_name(*lit->inferred_name());
582 fun->shared()->SetThisPropertyAssignmentsInfo(
583 lit->has_only_simple_this_property_assignments(),
584 *lit->this_property_assignments());
585 fun->shared()->set_try_fast_codegen(lit->try_fast_codegen());
586}
587
588
Steve Block3ce2e202009-11-05 08:53:23 +0000589CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) {
590 Scope* scope = fun->scope();
591
Steve Blockd0582a62009-12-15 09:54:21 +0000592 if (scope->num_heap_slots() > 0) {
593 // We support functions with a local context if they do not have
594 // parameters that need to be copied into the context.
595 for (int i = 0, len = scope->num_parameters(); i < len; i++) {
596 Slot* slot = scope->parameter(i)->slot();
597 if (slot != NULL && slot->type() == Slot::CONTEXT) {
598 if (FLAG_trace_bailout) {
599 PrintF("Function has context-allocated parameters.\n");
600 }
601 return NORMAL;
602 }
603 }
Steve Block3ce2e202009-11-05 08:53:23 +0000604 }
Steve Block3ce2e202009-11-05 08:53:23 +0000605
606 has_supported_syntax_ = true;
Steve Blockd0582a62009-12-15 09:54:21 +0000607 VisitDeclarations(scope->declarations());
Steve Block3ce2e202009-11-05 08:53:23 +0000608 if (!has_supported_syntax_) return NORMAL;
609
610 VisitStatements(fun->body());
611 return has_supported_syntax_ ? FAST : NORMAL;
612}
613
614
615#define BAILOUT(reason) \
616 do { \
617 if (FLAG_trace_bailout) { \
618 PrintF("%s\n", reason); \
619 } \
620 has_supported_syntax_ = false; \
621 return; \
622 } while (false)
623
624
625#define CHECK_BAILOUT \
626 do { \
627 if (!has_supported_syntax_) return; \
628 } while (false)
629
630
631void CodeGenSelector::VisitDeclarations(ZoneList<Declaration*>* decls) {
632 for (int i = 0; i < decls->length(); i++) {
633 Visit(decls->at(i));
634 CHECK_BAILOUT;
635 }
636}
637
638
639void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) {
640 for (int i = 0, len = stmts->length(); i < len; i++) {
641 Visit(stmts->at(i));
642 CHECK_BAILOUT;
643 }
644}
645
646
647void CodeGenSelector::VisitDeclaration(Declaration* decl) {
Steve Blockd0582a62009-12-15 09:54:21 +0000648 Property* prop = decl->proxy()->AsProperty();
649 if (prop != NULL) {
650 // Property rewrites are shared, ensure we are not changing its
651 // expression context state.
652 ASSERT(prop->obj()->context() == Expression::kUninitialized ||
653 prop->obj()->context() == Expression::kValue);
654 ASSERT(prop->key()->context() == Expression::kUninitialized ||
655 prop->key()->context() == Expression::kValue);
656 ProcessExpression(prop->obj(), Expression::kValue);
657 ProcessExpression(prop->key(), Expression::kValue);
658 }
659
660 if (decl->fun() != NULL) {
661 ProcessExpression(decl->fun(), Expression::kValue);
Steve Block3ce2e202009-11-05 08:53:23 +0000662 }
663}
664
665
666void CodeGenSelector::VisitBlock(Block* stmt) {
667 VisitStatements(stmt->statements());
668}
669
670
671void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) {
Steve Blockd0582a62009-12-15 09:54:21 +0000672 ProcessExpression(stmt->expression(), Expression::kEffect);
Steve Block3ce2e202009-11-05 08:53:23 +0000673}
674
675
676void CodeGenSelector::VisitEmptyStatement(EmptyStatement* stmt) {
677 // EmptyStatement is supported.
678}
679
680
681void CodeGenSelector::VisitIfStatement(IfStatement* stmt) {
Steve Blockd0582a62009-12-15 09:54:21 +0000682 ProcessExpression(stmt->condition(), Expression::kTest);
683 CHECK_BAILOUT;
684 Visit(stmt->then_statement());
685 CHECK_BAILOUT;
686 Visit(stmt->else_statement());
Steve Block3ce2e202009-11-05 08:53:23 +0000687}
688
689
690void CodeGenSelector::VisitContinueStatement(ContinueStatement* stmt) {
691 BAILOUT("ContinueStatement");
692}
693
694
695void CodeGenSelector::VisitBreakStatement(BreakStatement* stmt) {
696 BAILOUT("BreakStatement");
697}
698
699
700void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) {
Steve Blockd0582a62009-12-15 09:54:21 +0000701 ProcessExpression(stmt->expression(), Expression::kValue);
Steve Block3ce2e202009-11-05 08:53:23 +0000702}
703
704
705void CodeGenSelector::VisitWithEnterStatement(WithEnterStatement* stmt) {
706 BAILOUT("WithEnterStatement");
707}
708
709
710void CodeGenSelector::VisitWithExitStatement(WithExitStatement* stmt) {
711 BAILOUT("WithExitStatement");
712}
713
714
715void CodeGenSelector::VisitSwitchStatement(SwitchStatement* stmt) {
716 BAILOUT("SwitchStatement");
717}
718
719
720void CodeGenSelector::VisitDoWhileStatement(DoWhileStatement* stmt) {
Steve Blockd0582a62009-12-15 09:54:21 +0000721 // We do not handle loops with breaks or continue statements in their
722 // body. We will bailout when we hit those statements in the body.
723 ProcessExpression(stmt->cond(), Expression::kTest);
724 CHECK_BAILOUT;
725 Visit(stmt->body());
Steve Block3ce2e202009-11-05 08:53:23 +0000726}
727
728
729void CodeGenSelector::VisitWhileStatement(WhileStatement* stmt) {
Steve Blockd0582a62009-12-15 09:54:21 +0000730 // We do not handle loops with breaks or continue statements in their
731 // body. We will bailout when we hit those statements in the body.
732 ProcessExpression(stmt->cond(), Expression::kTest);
733 CHECK_BAILOUT;
734 Visit(stmt->body());
Steve Block3ce2e202009-11-05 08:53:23 +0000735}
736
737
738void CodeGenSelector::VisitForStatement(ForStatement* stmt) {
Steve Blockd0582a62009-12-15 09:54:21 +0000739 // We do not handle loops with breaks or continue statements in their
740 // body. We will bailout when we hit those statements in the body.
741 if (stmt->init() != NULL) {
742 Visit(stmt->init());
743 CHECK_BAILOUT;
744 }
745 if (stmt->cond() != NULL) {
746 ProcessExpression(stmt->cond(), Expression::kTest);
747 CHECK_BAILOUT;
748 }
749 Visit(stmt->body());
750 if (stmt->next() != NULL) {
751 CHECK_BAILOUT;
752 Visit(stmt->next());
753 }
Steve Block3ce2e202009-11-05 08:53:23 +0000754}
755
756
757void CodeGenSelector::VisitForInStatement(ForInStatement* stmt) {
758 BAILOUT("ForInStatement");
759}
760
761
762void CodeGenSelector::VisitTryCatchStatement(TryCatchStatement* stmt) {
763 BAILOUT("TryCatchStatement");
764}
765
766
767void CodeGenSelector::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
768 BAILOUT("TryFinallyStatement");
769}
770
771
772void CodeGenSelector::VisitDebuggerStatement(DebuggerStatement* stmt) {
Steve Blockd0582a62009-12-15 09:54:21 +0000773 // Debugger statement is supported.
Steve Block3ce2e202009-11-05 08:53:23 +0000774}
775
776
777void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +0000778 // Function literal is supported.
Steve Block3ce2e202009-11-05 08:53:23 +0000779}
780
781
782void CodeGenSelector::VisitFunctionBoilerplateLiteral(
783 FunctionBoilerplateLiteral* expr) {
784 BAILOUT("FunctionBoilerplateLiteral");
785}
786
787
788void CodeGenSelector::VisitConditional(Conditional* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +0000789 ProcessExpression(expr->condition(), Expression::kTest);
790 CHECK_BAILOUT;
791 ProcessExpression(expr->then_expression(), context_);
792 CHECK_BAILOUT;
793 ProcessExpression(expr->else_expression(), context_);
Steve Block3ce2e202009-11-05 08:53:23 +0000794}
795
796
797void CodeGenSelector::VisitSlot(Slot* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +0000798 UNREACHABLE();
Steve Block3ce2e202009-11-05 08:53:23 +0000799}
800
801
802void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
803 Expression* rewrite = expr->var()->rewrite();
Steve Blockd0582a62009-12-15 09:54:21 +0000804 // A rewrite of NULL indicates a global variable.
805 if (rewrite != NULL) {
806 // Non-global.
807 Slot* slot = rewrite->AsSlot();
808 if (slot != NULL) {
809 Slot::Type type = slot->type();
810 // When LOOKUP slots are enabled, some currently dead code
811 // implementing unary typeof will become live.
812 if (type == Slot::LOOKUP) {
813 BAILOUT("Lookup slot");
814 }
815 } else {
816#ifdef DEBUG
817 // Only remaining possibility is a property where the object is
818 // a slotted variable and the key is a smi.
819 Property* property = rewrite->AsProperty();
820 ASSERT_NOT_NULL(property);
821 Variable* object = property->obj()->AsVariableProxy()->AsVariable();
822 ASSERT_NOT_NULL(object);
823 ASSERT_NOT_NULL(object->slot());
824 ASSERT_NOT_NULL(property->key()->AsLiteral());
825 ASSERT(property->key()->AsLiteral()->handle()->IsSmi());
826#endif
827 }
828 }
Steve Block3ce2e202009-11-05 08:53:23 +0000829}
830
831
832void CodeGenSelector::VisitLiteral(Literal* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +0000833 /* Nothing to do. */
Steve Block3ce2e202009-11-05 08:53:23 +0000834}
835
836
837void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +0000838 /* Nothing to do. */
Steve Block3ce2e202009-11-05 08:53:23 +0000839}
840
841
842void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +0000843 ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
844
845 for (int i = 0, len = properties->length(); i < len; i++) {
846 ObjectLiteral::Property* property = properties->at(i);
847 if (property->IsCompileTimeValue()) continue;
848
849 switch (property->kind()) {
850 case ObjectLiteral::Property::CONSTANT:
851 UNREACHABLE();
852
853 // For (non-compile-time) materialized literals and computed
854 // properties with symbolic keys we will use an IC and therefore not
855 // generate code for the key.
856 case ObjectLiteral::Property::COMPUTED: // Fall through.
857 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
858 if (property->key()->handle()->IsSymbol()) {
859 break;
860 }
861 // Fall through.
862
863 // In all other cases we need the key's value on the stack
864 // for a runtime call. (Relies on TEMP meaning STACK.)
865 case ObjectLiteral::Property::GETTER: // Fall through.
866 case ObjectLiteral::Property::SETTER: // Fall through.
867 case ObjectLiteral::Property::PROTOTYPE:
868 ProcessExpression(property->key(), Expression::kValue);
869 CHECK_BAILOUT;
870 break;
871 }
872 ProcessExpression(property->value(), Expression::kValue);
873 CHECK_BAILOUT;
874 }
Steve Block3ce2e202009-11-05 08:53:23 +0000875}
876
877
878void CodeGenSelector::VisitArrayLiteral(ArrayLiteral* expr) {
879 ZoneList<Expression*>* subexprs = expr->values();
880 for (int i = 0, len = subexprs->length(); i < len; i++) {
881 Expression* subexpr = subexprs->at(i);
882 if (subexpr->AsLiteral() != NULL) continue;
883 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
Steve Blockd0582a62009-12-15 09:54:21 +0000884 ProcessExpression(subexpr, Expression::kValue);
Steve Block3ce2e202009-11-05 08:53:23 +0000885 CHECK_BAILOUT;
886 }
887}
888
889
890void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) {
891 BAILOUT("CatchExtensionObject");
892}
893
894
895void CodeGenSelector::VisitAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +0000896 // We support plain non-compound assignments to properties, parameters and
897 // non-context (stack-allocated) locals, and global variables.
Steve Block3ce2e202009-11-05 08:53:23 +0000898 Token::Value op = expr->op();
899 if (op == Token::INIT_CONST) BAILOUT("initialize constant");
900 if (op != Token::ASSIGN && op != Token::INIT_VAR) {
901 BAILOUT("compound assignment");
902 }
903
904 Variable* var = expr->target()->AsVariableProxy()->AsVariable();
Steve Blockd0582a62009-12-15 09:54:21 +0000905 Property* prop = expr->target()->AsProperty();
906 ASSERT(var == NULL || prop == NULL);
907 if (var != NULL) {
908 // All global variables are supported.
909 if (!var->is_global()) {
910 ASSERT(var->slot() != NULL);
911 Slot::Type type = var->slot()->type();
912 if (type == Slot::LOOKUP) {
913 BAILOUT("Lookup slot");
914 }
Steve Block3ce2e202009-11-05 08:53:23 +0000915 }
Steve Blockd0582a62009-12-15 09:54:21 +0000916 } else if (prop != NULL) {
917 ASSERT(prop->obj()->context() == Expression::kUninitialized ||
918 prop->obj()->context() == Expression::kValue);
919 ProcessExpression(prop->obj(), Expression::kValue);
920 CHECK_BAILOUT;
921 // We will only visit the key during code generation for keyed property
922 // stores. Leave its expression context uninitialized for named
923 // property stores.
924 Literal* lit = prop->key()->AsLiteral();
925 uint32_t ignored;
926 if (lit == NULL ||
927 !lit->handle()->IsSymbol() ||
928 String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) {
929 ASSERT(prop->key()->context() == Expression::kUninitialized ||
930 prop->key()->context() == Expression::kValue);
931 ProcessExpression(prop->key(), Expression::kValue);
932 CHECK_BAILOUT;
933 }
934 } else {
935 // This is a throw reference error.
936 BAILOUT("non-variable/non-property assignment");
Steve Block3ce2e202009-11-05 08:53:23 +0000937 }
938
Steve Blockd0582a62009-12-15 09:54:21 +0000939 ProcessExpression(expr->value(), Expression::kValue);
Steve Block3ce2e202009-11-05 08:53:23 +0000940}
941
942
943void CodeGenSelector::VisitThrow(Throw* expr) {
944 BAILOUT("Throw");
945}
946
947
948void CodeGenSelector::VisitProperty(Property* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +0000949 ProcessExpression(expr->obj(), Expression::kValue);
950 CHECK_BAILOUT;
951 ProcessExpression(expr->key(), Expression::kValue);
Steve Block3ce2e202009-11-05 08:53:23 +0000952}
953
954
955void CodeGenSelector::VisitCall(Call* expr) {
956 Expression* fun = expr->expression();
957 ZoneList<Expression*>* args = expr->arguments();
958 Variable* var = fun->AsVariableProxy()->AsVariable();
959
960 // Check for supported calls
961 if (var != NULL && var->is_possibly_eval()) {
Steve Blockd0582a62009-12-15 09:54:21 +0000962 BAILOUT("call to the identifier 'eval'");
Steve Block3ce2e202009-11-05 08:53:23 +0000963 } else if (var != NULL && !var->is_this() && var->is_global()) {
Steve Blockd0582a62009-12-15 09:54:21 +0000964 // Calls to global variables are supported.
965 } else if (var != NULL && var->slot() != NULL &&
966 var->slot()->type() == Slot::LOOKUP) {
967 BAILOUT("call to a lookup slot");
968 } else if (fun->AsProperty() != NULL) {
969 Property* prop = fun->AsProperty();
970 Literal* literal_key = prop->key()->AsLiteral();
971 if (literal_key != NULL && literal_key->handle()->IsSymbol()) {
972 ProcessExpression(prop->obj(), Expression::kValue);
973 CHECK_BAILOUT;
974 } else {
975 ProcessExpression(prop->obj(), Expression::kValue);
976 CHECK_BAILOUT;
977 ProcessExpression(prop->key(), Expression::kValue);
978 CHECK_BAILOUT;
979 }
Steve Block3ce2e202009-11-05 08:53:23 +0000980 } else {
Steve Blockd0582a62009-12-15 09:54:21 +0000981 // Otherwise the call is supported if the function expression is.
982 ProcessExpression(fun, Expression::kValue);
Steve Block3ce2e202009-11-05 08:53:23 +0000983 }
Steve Blockd0582a62009-12-15 09:54:21 +0000984 // Check all arguments to the call.
Steve Block3ce2e202009-11-05 08:53:23 +0000985 for (int i = 0; i < args->length(); i++) {
Steve Blockd0582a62009-12-15 09:54:21 +0000986 ProcessExpression(args->at(i), Expression::kValue);
Steve Block3ce2e202009-11-05 08:53:23 +0000987 CHECK_BAILOUT;
988 }
989}
990
991
992void CodeGenSelector::VisitCallNew(CallNew* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +0000993 ProcessExpression(expr->expression(), Expression::kValue);
994 CHECK_BAILOUT;
995 ZoneList<Expression*>* args = expr->arguments();
996 // Check all arguments to the call
997 for (int i = 0; i < args->length(); i++) {
998 ProcessExpression(args->at(i), Expression::kValue);
999 CHECK_BAILOUT;
1000 }
Steve Block3ce2e202009-11-05 08:53:23 +00001001}
1002
1003
1004void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001005 // Check for inline runtime call
1006 if (expr->name()->Get(0) == '_' &&
1007 CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
Steve Blockd0582a62009-12-15 09:54:21 +00001008 BAILOUT("inlined runtime call");
Steve Block3ce2e202009-11-05 08:53:23 +00001009 }
Steve Blockd0582a62009-12-15 09:54:21 +00001010 // Check all arguments to the call. (Relies on TEMP meaning STACK.)
Steve Block3ce2e202009-11-05 08:53:23 +00001011 for (int i = 0; i < expr->arguments()->length(); i++) {
Steve Blockd0582a62009-12-15 09:54:21 +00001012 ProcessExpression(expr->arguments()->at(i), Expression::kValue);
Steve Block3ce2e202009-11-05 08:53:23 +00001013 CHECK_BAILOUT;
1014 }
1015}
1016
1017
1018void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001019 switch (expr->op()) {
1020 case Token::VOID:
1021 ProcessExpression(expr->expression(), Expression::kEffect);
1022 break;
1023 case Token::NOT:
1024 ProcessExpression(expr->expression(), Expression::kTest);
1025 break;
1026 case Token::TYPEOF:
1027 ProcessExpression(expr->expression(), Expression::kValue);
1028 break;
1029 default:
1030 BAILOUT("UnaryOperation");
1031 }
Steve Block3ce2e202009-11-05 08:53:23 +00001032}
1033
1034
1035void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001036 // We support postfix count operations on global variables.
1037 if (expr->is_prefix()) BAILOUT("Prefix CountOperation");
1038 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
1039 if (var == NULL || !var->is_global()) BAILOUT("non-global postincrement");
1040 ProcessExpression(expr->expression(), Expression::kValue);
Steve Block3ce2e202009-11-05 08:53:23 +00001041}
1042
1043
1044void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
1045 switch (expr->op()) {
Steve Blockd0582a62009-12-15 09:54:21 +00001046 case Token::COMMA:
1047 ProcessExpression(expr->left(), Expression::kEffect);
Steve Block3ce2e202009-11-05 08:53:23 +00001048 CHECK_BAILOUT;
Steve Blockd0582a62009-12-15 09:54:21 +00001049 ProcessExpression(expr->right(), context_);
1050 break;
1051
1052 case Token::OR:
1053 switch (context_) {
1054 case Expression::kUninitialized:
1055 UNREACHABLE();
1056 case Expression::kEffect: // Fall through.
1057 case Expression::kTest: // Fall through.
1058 case Expression::kTestValue:
1059 // The left subexpression's value is not needed, it is in a pure
1060 // test context.
1061 ProcessExpression(expr->left(), Expression::kTest);
1062 break;
1063 case Expression::kValue: // Fall through.
1064 case Expression::kValueTest:
1065 // The left subexpression's value is needed, it is in a hybrid
1066 // value/test context.
1067 ProcessExpression(expr->left(), Expression::kValueTest);
1068 break;
1069 }
1070 CHECK_BAILOUT;
1071 ProcessExpression(expr->right(), context_);
1072 break;
1073
1074 case Token::AND:
1075 switch (context_) {
1076 case Expression::kUninitialized:
1077 UNREACHABLE();
1078 case Expression::kEffect: // Fall through.
1079 case Expression::kTest: // Fall through.
1080 case Expression::kValueTest:
1081 // The left subexpression's value is not needed, it is in a pure
1082 // test context.
1083 ProcessExpression(expr->left(), Expression::kTest);
1084 break;
1085 case Expression::kValue: // Fall through.
1086 case Expression::kTestValue:
1087 // The left subexpression's value is needed, it is in a hybrid
1088 // test/value context.
1089 ProcessExpression(expr->left(), Expression::kTestValue);
1090 break;
1091 }
1092 CHECK_BAILOUT;
1093 ProcessExpression(expr->right(), context_);
1094 break;
1095
1096 case Token::ADD:
1097 case Token::SUB:
1098 case Token::DIV:
1099 case Token::MOD:
1100 case Token::MUL:
1101 case Token::BIT_OR:
1102 case Token::BIT_AND:
1103 case Token::BIT_XOR:
1104 case Token::SHL:
1105 case Token::SHR:
1106 case Token::SAR:
1107 ProcessExpression(expr->left(), Expression::kValue);
1108 CHECK_BAILOUT;
1109 ProcessExpression(expr->right(), Expression::kValue);
Steve Block3ce2e202009-11-05 08:53:23 +00001110 break;
1111
1112 default:
1113 BAILOUT("Unsupported binary operation");
1114 }
1115}
1116
1117
1118void CodeGenSelector::VisitCompareOperation(CompareOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001119 ProcessExpression(expr->left(), Expression::kValue);
1120 CHECK_BAILOUT;
1121 ProcessExpression(expr->right(), Expression::kValue);
Steve Block3ce2e202009-11-05 08:53:23 +00001122}
1123
1124
1125void CodeGenSelector::VisitThisFunction(ThisFunction* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001126 // ThisFunction is supported.
Steve Block3ce2e202009-11-05 08:53:23 +00001127}
1128
1129#undef BAILOUT
1130#undef CHECK_BAILOUT
1131
1132
Steve Blocka7e24c12009-10-30 11:49:00 +00001133} } // namespace v8::internal