blob: b7aaedf5228b5ff33e3c453123f83b99ce5f54e7 [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 Clarkeeab96aa2010-01-27 16:31:12 +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
Leon Clarkeeab96aa2010-01-27 16:31:12 +000045class CodeGenSelector: public AstVisitor {
46 public:
47 enum CodeGenTag { NORMAL, FAST };
48
49 CodeGenSelector() : has_supported_syntax_(true) {}
50
51 CodeGenTag Select(FunctionLiteral* fun);
52
53 private:
54 void VisitDeclarations(ZoneList<Declaration*>* decls);
55 void VisitStatements(ZoneList<Statement*>* stmts);
56
57 // AST node visit functions.
58#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
59 AST_NODE_LIST(DECLARE_VISIT)
60#undef DECLARE_VISIT
61
62 bool has_supported_syntax_;
63
64 DISALLOW_COPY_AND_ASSIGN(CodeGenSelector);
65};
66
67
Steve Blocka7e24c12009-10-30 11:49:00 +000068static Handle<Code> MakeCode(FunctionLiteral* literal,
69 Handle<Script> script,
70 Handle<Context> context,
Steve Blockd0582a62009-12-15 09:54:21 +000071 bool is_eval,
72 Handle<SharedFunctionInfo> shared) {
Steve Blocka7e24c12009-10-30 11:49:00 +000073 ASSERT(literal != NULL);
74
75 // Rewrite the AST by introducing .result assignments where needed.
76 if (!Rewriter::Process(literal) || !AnalyzeVariableUsage(literal)) {
77 // 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 }
81
82 {
83 // Compute top scope and allocate variables. For lazy compilation
84 // the top scope only contains the single lazily compiled function,
85 // so this doesn't re-allocate variables repeatedly.
86 HistogramTimerScope timer(&Counters::variable_allocation);
87 Scope* top = literal->scope();
88 while (top->outer_scope() != NULL) top = top->outer_scope();
89 top->AllocateVariables(context);
90 }
91
92#ifdef DEBUG
93 if (Bootstrapper::IsActive() ?
94 FLAG_print_builtin_scopes :
95 FLAG_print_scopes) {
96 literal->scope()->Print();
97 }
98#endif
99
100 // Optimize the AST.
101 if (!Rewriter::Optimize(literal)) {
102 // Signal a stack overflow by returning a null handle. The stack
103 // overflow exception will be thrown by the caller.
104 return Handle<Code>::null();
105 }
106
107 // Generate code and return it.
Steve Block3ce2e202009-11-05 08:53:23 +0000108 if (FLAG_fast_compiler) {
Steve Blockd0582a62009-12-15 09:54:21 +0000109 // If there is no shared function info, try the fast code
110 // generator for code in the global scope. Otherwise obey the
111 // explicit hint in the shared function info.
112 // If always_fast_compiler is true, always try the fast compiler.
113 if (shared.is_null() && !literal->scope()->is_global_scope() &&
114 !FLAG_always_fast_compiler) {
115 if (FLAG_trace_bailout) PrintF("Non-global scope\n");
116 } else if (!shared.is_null() && !shared->try_fast_codegen() &&
117 !FLAG_always_fast_compiler) {
118 if (FLAG_trace_bailout) PrintF("No hint to try fast\n");
119 } else {
Leon Clarkeeab96aa2010-01-27 16:31:12 +0000120 CodeGenSelector selector;
121 CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
122 if (code_gen == CodeGenSelector::FAST) {
123 return FastCodeGenerator::MakeCode(literal, script, is_eval);
Steve Blockd0582a62009-12-15 09:54:21 +0000124 }
Leon Clarkeeab96aa2010-01-27 16:31:12 +0000125 ASSERT(code_gen == CodeGenSelector::NORMAL);
Steve Block3ce2e202009-11-05 08:53:23 +0000126 }
Steve Block3ce2e202009-11-05 08:53:23 +0000127 }
128 return CodeGenerator::MakeCode(literal, script, is_eval);
Steve Blocka7e24c12009-10-30 11:49:00 +0000129}
130
131
132static bool IsValidJSON(FunctionLiteral* lit) {
133 if (lit->body()->length() != 1)
134 return false;
135 Statement* stmt = lit->body()->at(0);
136 if (stmt->AsExpressionStatement() == NULL)
137 return false;
138 Expression* expr = stmt->AsExpressionStatement()->expression();
139 return expr->IsValidJSON();
140}
141
142
143static Handle<JSFunction> MakeFunction(bool is_global,
144 bool is_eval,
145 Compiler::ValidationState validate,
146 Handle<Script> script,
147 Handle<Context> context,
148 v8::Extension* extension,
149 ScriptDataImpl* pre_data) {
150 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
151
152 PostponeInterruptsScope postpone;
153
154 ASSERT(!i::Top::global_context().is_null());
155 script->set_context_data((*i::Top::global_context())->data());
156
157#ifdef ENABLE_DEBUGGER_SUPPORT
158 bool is_json = (validate == Compiler::VALIDATE_JSON);
159 if (is_eval || is_json) {
160 script->set_compilation_type(
161 is_json ? Smi::FromInt(Script::COMPILATION_TYPE_JSON) :
162 Smi::FromInt(Script::COMPILATION_TYPE_EVAL));
163 // For eval scripts add information on the function from which eval was
164 // called.
165 if (is_eval) {
166 JavaScriptFrameIterator it;
Steve Blockd0582a62009-12-15 09:54:21 +0000167 script->set_eval_from_shared(
168 JSFunction::cast(it.frame()->function())->shared());
169 int offset = static_cast<int>(
170 it.frame()->pc() - it.frame()->code()->instruction_start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000171 script->set_eval_from_instructions_offset(Smi::FromInt(offset));
172 }
173 }
174
175 // Notify debugger
176 Debugger::OnBeforeCompile(script);
177#endif
178
179 // Only allow non-global compiles for eval.
180 ASSERT(is_eval || is_global);
181
182 // Build AST.
183 FunctionLiteral* lit = MakeAST(is_global, script, extension, pre_data);
184
185 // Check for parse errors.
186 if (lit == NULL) {
187 ASSERT(Top::has_pending_exception());
188 return Handle<JSFunction>::null();
189 }
190
191 // When parsing JSON we do an ordinary parse and then afterwards
192 // check the AST to ensure it was well-formed. If not we give a
193 // syntax error.
194 if (validate == Compiler::VALIDATE_JSON && !IsValidJSON(lit)) {
195 HandleScope scope;
196 Handle<JSArray> args = Factory::NewJSArray(1);
197 Handle<Object> source(script->source());
198 SetElement(args, 0, source);
199 Handle<Object> result = Factory::NewSyntaxError("invalid_json", args);
200 Top::Throw(*result, NULL);
201 return Handle<JSFunction>::null();
202 }
203
204 // Measure how long it takes to do the compilation; only take the
205 // rest of the function into account to avoid overlap with the
206 // parsing statistics.
207 HistogramTimer* rate = is_eval
208 ? &Counters::compile_eval
209 : &Counters::compile;
210 HistogramTimerScope timer(rate);
211
212 // Compile the code.
Steve Blockd0582a62009-12-15 09:54:21 +0000213 Handle<Code> code = MakeCode(lit, script, context, is_eval,
214 Handle<SharedFunctionInfo>::null());
Steve Blocka7e24c12009-10-30 11:49:00 +0000215
216 // Check for stack-overflow exceptions.
217 if (code.is_null()) {
218 Top::StackOverflow();
219 return Handle<JSFunction>::null();
220 }
221
222#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
223 // Log the code generation for the script. Check explicit whether logging is
224 // to avoid allocating when not required.
225 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
226 if (script->name()->IsString()) {
227 SmartPointer<char> data =
228 String::cast(script->name())->ToCString(DISALLOW_NULLS);
229 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
230 *code, *data));
231 OProfileAgent::CreateNativeCodeRegion(*data,
232 code->instruction_start(),
233 code->instruction_size());
234 } else {
235 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
236 *code, ""));
237 OProfileAgent::CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
238 code->instruction_start(),
239 code->instruction_size());
240 }
241 }
242#endif
243
244 // Allocate function.
245 Handle<JSFunction> fun =
246 Factory::NewFunctionBoilerplate(lit->name(),
247 lit->materialized_literal_count(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000248 code);
249
250 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
Steve Blockd0582a62009-12-15 09:54:21 +0000251 Compiler::SetFunctionInfo(fun, lit, true, script);
Steve Blocka7e24c12009-10-30 11:49:00 +0000252
253 // Hint to the runtime system used when allocating space for initial
254 // property space by setting the expected number of properties for
255 // the instances of the function.
256 SetExpectedNofPropertiesFromEstimate(fun, lit->expected_property_count());
257
258#ifdef ENABLE_DEBUGGER_SUPPORT
259 // Notify debugger
260 Debugger::OnAfterCompile(script, fun);
261#endif
262
263 return fun;
264}
265
266
267static StaticResource<SafeStringInputBuffer> safe_string_input_buffer;
268
269
270Handle<JSFunction> Compiler::Compile(Handle<String> source,
271 Handle<Object> script_name,
272 int line_offset, int column_offset,
273 v8::Extension* extension,
274 ScriptDataImpl* input_pre_data) {
275 int source_length = source->length();
276 Counters::total_load_size.Increment(source_length);
277 Counters::total_compile_size.Increment(source_length);
278
279 // The VM is in the COMPILER state until exiting this function.
280 VMState state(COMPILER);
281
282 // Do a lookup in the compilation cache but not for extensions.
283 Handle<JSFunction> result;
284 if (extension == NULL) {
285 result = CompilationCache::LookupScript(source,
286 script_name,
287 line_offset,
288 column_offset);
289 }
290
291 if (result.is_null()) {
292 // No cache entry found. Do pre-parsing and compile the script.
293 ScriptDataImpl* pre_data = input_pre_data;
294 if (pre_data == NULL && source_length >= FLAG_min_preparse_length) {
295 Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
296 buf->Reset(source.location());
297 pre_data = PreParse(source, buf.value(), extension);
298 }
299
300 // Create a script object describing the script to be compiled.
301 Handle<Script> script = Factory::NewScript(source);
302 if (!script_name.is_null()) {
303 script->set_name(*script_name);
304 script->set_line_offset(Smi::FromInt(line_offset));
305 script->set_column_offset(Smi::FromInt(column_offset));
306 }
307
308 // Compile the function and add it to the cache.
309 result = MakeFunction(true,
310 false,
311 DONT_VALIDATE_JSON,
312 script,
313 Handle<Context>::null(),
314 extension,
315 pre_data);
316 if (extension == NULL && !result.is_null()) {
317 CompilationCache::PutScript(source, result);
318 }
319
320 // Get rid of the pre-parsing data (if necessary).
321 if (input_pre_data == NULL && pre_data != NULL) {
322 delete pre_data;
323 }
324 }
325
326 if (result.is_null()) Top::ReportPendingMessages();
327 return result;
328}
329
330
331Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
332 Handle<Context> context,
333 bool is_global,
334 ValidationState validate) {
335 // Note that if validation is required then no path through this
336 // function is allowed to return a value without validating that
337 // the input is legal json.
338
339 int source_length = source->length();
340 Counters::total_eval_size.Increment(source_length);
341 Counters::total_compile_size.Increment(source_length);
342
343 // The VM is in the COMPILER state until exiting this function.
344 VMState state(COMPILER);
345
346 // Do a lookup in the compilation cache; if the entry is not there,
347 // invoke the compiler and add the result to the cache. If we're
348 // evaluating json we bypass the cache since we can't be sure a
349 // potential value in the cache has been validated.
350 Handle<JSFunction> result;
351 if (validate == DONT_VALIDATE_JSON)
352 result = CompilationCache::LookupEval(source, context, is_global);
353
354 if (result.is_null()) {
355 // Create a script object describing the script to be compiled.
356 Handle<Script> script = Factory::NewScript(source);
357 result = MakeFunction(is_global,
358 true,
359 validate,
360 script,
361 context,
362 NULL,
363 NULL);
364 if (!result.is_null() && validate != VALIDATE_JSON) {
365 // For json it's unlikely that we'll ever see exactly the same
366 // string again so we don't use the compilation cache.
367 CompilationCache::PutEval(source, context, is_global, result);
368 }
369 }
370
371 return result;
372}
373
374
375bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
376 int loop_nesting) {
377 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
378
379 // The VM is in the COMPILER state until exiting this function.
380 VMState state(COMPILER);
381
382 PostponeInterruptsScope postpone;
383
384 // Compute name, source code and script data.
385 Handle<String> name(String::cast(shared->name()));
386 Handle<Script> script(Script::cast(shared->script()));
387
388 int start_position = shared->start_position();
389 int end_position = shared->end_position();
390 bool is_expression = shared->is_expression();
391 Counters::total_compile_size.Increment(end_position - start_position);
392
393 // Generate the AST for the lazily compiled function. The AST may be
394 // NULL in case of parser stack overflow.
395 FunctionLiteral* lit = MakeLazyAST(script, name,
396 start_position,
397 end_position,
398 is_expression);
399
400 // Check for parse errors.
401 if (lit == NULL) {
402 ASSERT(Top::has_pending_exception());
403 return false;
404 }
405
406 // Update the loop nesting in the function literal.
407 lit->set_loop_nesting(loop_nesting);
408
409 // Measure how long it takes to do the lazy compilation; only take
410 // the rest of the function into account to avoid overlap with the
411 // lazy parsing statistics.
412 HistogramTimerScope timer(&Counters::compile_lazy);
413
414 // Compile the code.
Steve Blockd0582a62009-12-15 09:54:21 +0000415 Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false,
416 shared);
Steve Blocka7e24c12009-10-30 11:49:00 +0000417
418 // Check for stack-overflow exception.
419 if (code.is_null()) {
420 Top::StackOverflow();
421 return false;
422 }
423
424#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
425 // Log the code generation. If source information is available include script
426 // name and line number. Check explicit whether logging is enabled as finding
427 // the line number is not for free.
428 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
429 Handle<String> func_name(name->length() > 0 ?
430 *name : shared->inferred_name());
431 if (script->name()->IsString()) {
432 int line_num = GetScriptLineNumber(script, start_position) + 1;
433 LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name,
434 String::cast(script->name()), line_num));
435 OProfileAgent::CreateNativeCodeRegion(*func_name,
436 String::cast(script->name()),
437 line_num,
438 code->instruction_start(),
439 code->instruction_size());
440 } else {
441 LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name));
442 OProfileAgent::CreateNativeCodeRegion(*func_name,
443 code->instruction_start(),
444 code->instruction_size());
445 }
446 }
447#endif
448
449 // Update the shared function info with the compiled code.
450 shared->set_code(*code);
451
452 // Set the expected number of properties for instances.
453 SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
454
455 // Set the optimication hints after performing lazy compilation, as these are
456 // not set when the function is set up as a lazily compiled function.
457 shared->SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +0000458 lit->has_only_simple_this_property_assignments(),
459 *lit->this_property_assignments());
460
461 // Check the function has compiled code.
462 ASSERT(shared->is_compiled());
463 return true;
464}
465
466
Steve Blockd0582a62009-12-15 09:54:21 +0000467Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
468 Handle<Script> script,
469 AstVisitor* caller) {
470#ifdef DEBUG
471 // We should not try to compile the same function literal more than
472 // once.
473 literal->mark_as_compiled();
474#endif
475
476 // Determine if the function can be lazily compiled. This is
477 // necessary to allow some of our builtin JS files to be lazily
478 // compiled. These builtins cannot be handled lazily by the parser,
479 // since we have to know if a function uses the special natives
480 // syntax, which is something the parser records.
481 bool allow_lazy = literal->AllowsLazyCompilation();
482
483 // Generate code
484 Handle<Code> code;
485 if (FLAG_lazy && allow_lazy) {
486 code = ComputeLazyCompile(literal->num_parameters());
487 } else {
488 // The bodies of function literals have not yet been visited by
489 // the AST optimizer/analyzer.
490 if (!Rewriter::Optimize(literal)) {
491 return Handle<JSFunction>::null();
492 }
493
494 // Generate code and return it.
495 bool is_compiled = false;
Leon Clarkeeab96aa2010-01-27 16:31:12 +0000496 if (FLAG_fast_compiler && literal->try_fast_codegen()) {
497 CodeGenSelector selector;
498 CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
499 if (code_gen == CodeGenSelector::FAST) {
500 code = FastCodeGenerator::MakeCode(literal,
Steve Blockd0582a62009-12-15 09:54:21 +0000501 script,
502 false); // Not eval.
503 is_compiled = true;
504 }
505 }
506
507 if (!is_compiled) {
508 // We didn't try the fast compiler, or we failed to select it.
509 code = CodeGenerator::MakeCode(literal,
510 script,
511 false); // Not eval.
512 }
513
514 // Check for stack-overflow exception.
515 if (code.is_null()) {
516 caller->SetStackOverflow();
517 return Handle<JSFunction>::null();
518 }
519
520 // Function compilation complete.
521 LOG(CodeCreateEvent(Logger::FUNCTION_TAG, *code, *literal->name()));
522
523#ifdef ENABLE_OPROFILE_AGENT
Leon Clarkee46be812010-01-19 14:06:41 +0000524 OProfileAgent::CreateNativeCodeRegion(*literal->name(),
Steve Blockd0582a62009-12-15 09:54:21 +0000525 code->instruction_start(),
526 code->instruction_size());
527#endif
528 }
529
530 // Create a boilerplate function.
531 Handle<JSFunction> function =
532 Factory::NewFunctionBoilerplate(literal->name(),
533 literal->materialized_literal_count(),
534 code);
535 SetFunctionInfo(function, literal, false, script);
536
537#ifdef ENABLE_DEBUGGER_SUPPORT
538 // Notify debugger that a new function has been added.
539 Debugger::OnNewFunction(function);
540#endif
541
542 // Set the expected number of properties for instances and return
543 // the resulting function.
544 SetExpectedNofPropertiesFromEstimate(function,
545 literal->expected_property_count());
546 return function;
547}
548
549
550// Sets the function info on a function.
551// The start_position points to the first '(' character after the function name
552// in the full script source. When counting characters in the script source the
553// the first character is number 0 (not 1).
554void Compiler::SetFunctionInfo(Handle<JSFunction> fun,
555 FunctionLiteral* lit,
556 bool is_toplevel,
557 Handle<Script> script) {
558 fun->shared()->set_length(lit->num_parameters());
559 fun->shared()->set_formal_parameter_count(lit->num_parameters());
560 fun->shared()->set_script(*script);
561 fun->shared()->set_function_token_position(lit->function_token_position());
562 fun->shared()->set_start_position(lit->start_position());
563 fun->shared()->set_end_position(lit->end_position());
564 fun->shared()->set_is_expression(lit->is_expression());
565 fun->shared()->set_is_toplevel(is_toplevel);
566 fun->shared()->set_inferred_name(*lit->inferred_name());
567 fun->shared()->SetThisPropertyAssignmentsInfo(
568 lit->has_only_simple_this_property_assignments(),
569 *lit->this_property_assignments());
570 fun->shared()->set_try_fast_codegen(lit->try_fast_codegen());
571}
572
573
Leon Clarkeeab96aa2010-01-27 16:31:12 +0000574CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) {
575 Scope* scope = fun->scope();
576
577 if (scope->num_heap_slots() > 0) {
578 // We support functions with a local context if they do not have
579 // parameters that need to be copied into the context.
580 for (int i = 0, len = scope->num_parameters(); i < len; i++) {
581 Slot* slot = scope->parameter(i)->slot();
582 if (slot != NULL && slot->type() == Slot::CONTEXT) {
583 if (FLAG_trace_bailout) {
584 PrintF("Function has context-allocated parameters.\n");
585 }
586 return NORMAL;
587 }
588 }
589 }
590
591 has_supported_syntax_ = true;
592 VisitDeclarations(scope->declarations());
593 if (!has_supported_syntax_) return NORMAL;
594
595 VisitStatements(fun->body());
596 return has_supported_syntax_ ? FAST : NORMAL;
597}
598
599
600#define BAILOUT(reason) \
601 do { \
602 if (FLAG_trace_bailout) { \
603 PrintF("%s\n", reason); \
604 } \
605 has_supported_syntax_ = false; \
606 return; \
607 } while (false)
608
609
610#define CHECK_BAILOUT \
611 do { \
612 if (!has_supported_syntax_) return; \
613 } while (false)
614
615
616void CodeGenSelector::VisitDeclarations(ZoneList<Declaration*>* decls) {
617 for (int i = 0; i < decls->length(); i++) {
618 Visit(decls->at(i));
619 CHECK_BAILOUT;
620 }
621}
622
623
624void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) {
625 for (int i = 0, len = stmts->length(); i < len; i++) {
626 Visit(stmts->at(i));
627 CHECK_BAILOUT;
628 }
629}
630
631
632void CodeGenSelector::VisitDeclaration(Declaration* decl) {
633 Property* prop = decl->proxy()->AsProperty();
634 if (prop != NULL) {
635 Visit(prop->obj());
636 Visit(prop->key());
637 }
638
639 if (decl->fun() != NULL) {
640 Visit(decl->fun());
641 }
642}
643
644
645void CodeGenSelector::VisitBlock(Block* stmt) {
646 VisitStatements(stmt->statements());
647}
648
649
650void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) {
651 Visit(stmt->expression());
652}
653
654
655void CodeGenSelector::VisitEmptyStatement(EmptyStatement* stmt) {}
656
657
658void CodeGenSelector::VisitIfStatement(IfStatement* stmt) {
659 Visit(stmt->condition());
660 CHECK_BAILOUT;
661 Visit(stmt->then_statement());
662 CHECK_BAILOUT;
663 Visit(stmt->else_statement());
664}
665
666
667void CodeGenSelector::VisitContinueStatement(ContinueStatement* stmt) {}
668
669
670void CodeGenSelector::VisitBreakStatement(BreakStatement* stmt) {}
671
672
673void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) {
674 Visit(stmt->expression());
675}
676
677
678void CodeGenSelector::VisitWithEnterStatement(WithEnterStatement* stmt) {
679 Visit(stmt->expression());
680}
681
682
683void CodeGenSelector::VisitWithExitStatement(WithExitStatement* stmt) {}
684
685
686void CodeGenSelector::VisitSwitchStatement(SwitchStatement* stmt) {
687 BAILOUT("SwitchStatement");
688}
689
690
691void CodeGenSelector::VisitDoWhileStatement(DoWhileStatement* stmt) {
692 Visit(stmt->cond());
693 CHECK_BAILOUT;
694 Visit(stmt->body());
695}
696
697
698void CodeGenSelector::VisitWhileStatement(WhileStatement* stmt) {
699 Visit(stmt->cond());
700 CHECK_BAILOUT;
701 Visit(stmt->body());
702}
703
704
705void CodeGenSelector::VisitForStatement(ForStatement* stmt) {
706 BAILOUT("ForStatement");
707}
708
709
710void CodeGenSelector::VisitForInStatement(ForInStatement* stmt) {
711 BAILOUT("ForInStatement");
712}
713
714
715void CodeGenSelector::VisitTryCatchStatement(TryCatchStatement* stmt) {
716 Visit(stmt->try_block());
717 CHECK_BAILOUT;
718 Visit(stmt->catch_block());
719}
720
721
722void CodeGenSelector::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
723 Visit(stmt->try_block());
724 CHECK_BAILOUT;
725 Visit(stmt->finally_block());
726}
727
728
729void CodeGenSelector::VisitDebuggerStatement(DebuggerStatement* stmt) {}
730
731
732void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) {}
733
734
735void CodeGenSelector::VisitFunctionBoilerplateLiteral(
736 FunctionBoilerplateLiteral* expr) {
737 BAILOUT("FunctionBoilerplateLiteral");
738}
739
740
741void CodeGenSelector::VisitConditional(Conditional* expr) {
742 Visit(expr->condition());
743 CHECK_BAILOUT;
744 Visit(expr->then_expression());
745 CHECK_BAILOUT;
746 Visit(expr->else_expression());
747}
748
749
750void CodeGenSelector::VisitSlot(Slot* expr) {
751 UNREACHABLE();
752}
753
754
755void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
756 Variable* var = expr->var();
757 if (!var->is_global()) {
758 Slot* slot = var->slot();
759 if (slot != NULL) {
760 Slot::Type type = slot->type();
761 // When LOOKUP slots are enabled, some currently dead code
762 // implementing unary typeof will become live.
763 if (type == Slot::LOOKUP) {
764 BAILOUT("Lookup slot");
765 }
766 } else {
767 // If not global or a slot, it is a parameter rewritten to an explicit
768 // property reference on the (shadow) arguments object.
769#ifdef DEBUG
770 Property* property = var->AsProperty();
771 ASSERT_NOT_NULL(property);
772 Variable* object = property->obj()->AsVariableProxy()->AsVariable();
773 ASSERT_NOT_NULL(object);
774 ASSERT_NOT_NULL(object->slot());
775 ASSERT_NOT_NULL(property->key()->AsLiteral());
776 ASSERT(property->key()->AsLiteral()->handle()->IsSmi());
777#endif
778 }
779 }
780}
781
782
783void CodeGenSelector::VisitLiteral(Literal* expr) {}
784
785
786void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) {}
787
788
789void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) {
790 ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
791
792 for (int i = 0, len = properties->length(); i < len; i++) {
793 ObjectLiteral::Property* property = properties->at(i);
794 if (property->IsCompileTimeValue()) continue;
795 Visit(property->key());
796 CHECK_BAILOUT;
797 Visit(property->value());
798 CHECK_BAILOUT;
799 }
800}
801
802
803void CodeGenSelector::VisitArrayLiteral(ArrayLiteral* expr) {
804 ZoneList<Expression*>* subexprs = expr->values();
805 for (int i = 0, len = subexprs->length(); i < len; i++) {
806 Expression* subexpr = subexprs->at(i);
807 if (subexpr->AsLiteral() != NULL) continue;
808 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
809 Visit(subexpr);
810 CHECK_BAILOUT;
811 }
812}
813
814
815void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) {
816 Visit(expr->key());
817 CHECK_BAILOUT;
818 Visit(expr->value());
819}
820
821
822void CodeGenSelector::VisitAssignment(Assignment* expr) {
823 // We support plain non-compound assignments to properties, parameters and
824 // non-context (stack-allocated) locals, and global variables.
825 Token::Value op = expr->op();
826 if (op == Token::INIT_CONST) BAILOUT("initialize constant");
827
828 Variable* var = expr->target()->AsVariableProxy()->AsVariable();
829 Property* prop = expr->target()->AsProperty();
830 ASSERT(var == NULL || prop == NULL);
831 if (var != NULL) {
832 if (var->mode() == Variable::CONST) {
833 BAILOUT("Assignment to const");
834 }
835 // All global variables are supported.
836 if (!var->is_global()) {
837 ASSERT(var->slot() != NULL);
838 Slot::Type type = var->slot()->type();
839 if (type == Slot::LOOKUP) {
840 BAILOUT("Lookup slot");
841 }
842 }
843 } else if (prop != NULL) {
844 Visit(prop->obj());
845 CHECK_BAILOUT;
846 Visit(prop->key());
847 CHECK_BAILOUT;
848 } else {
849 // This is a throw reference error.
850 BAILOUT("non-variable/non-property assignment");
851 }
852
853 Visit(expr->value());
854}
855
856
857void CodeGenSelector::VisitThrow(Throw* expr) {
858 Visit(expr->exception());
859}
860
861
862void CodeGenSelector::VisitProperty(Property* expr) {
863 Visit(expr->obj());
864 CHECK_BAILOUT;
865 Visit(expr->key());
866}
867
868
869void CodeGenSelector::VisitCall(Call* expr) {
870 Expression* fun = expr->expression();
871 ZoneList<Expression*>* args = expr->arguments();
872 Variable* var = fun->AsVariableProxy()->AsVariable();
873
874 // Check for supported calls
875 if (var != NULL && var->is_possibly_eval()) {
876 BAILOUT("call to the identifier 'eval'");
877 } else if (var != NULL && !var->is_this() && var->is_global()) {
878 // Calls to global variables are supported.
879 } else if (var != NULL && var->slot() != NULL &&
880 var->slot()->type() == Slot::LOOKUP) {
881 BAILOUT("call to a lookup slot");
882 } else if (fun->AsProperty() != NULL) {
883 Property* prop = fun->AsProperty();
884 Visit(prop->obj());
885 CHECK_BAILOUT;
886 Visit(prop->key());
887 CHECK_BAILOUT;
888 } else {
889 // Otherwise the call is supported if the function expression is.
890 Visit(fun);
891 }
892 // Check all arguments to the call.
893 for (int i = 0; i < args->length(); i++) {
894 Visit(args->at(i));
895 CHECK_BAILOUT;
896 }
897}
898
899
900void CodeGenSelector::VisitCallNew(CallNew* expr) {
901 Visit(expr->expression());
902 CHECK_BAILOUT;
903 ZoneList<Expression*>* args = expr->arguments();
904 // Check all arguments to the call
905 for (int i = 0; i < args->length(); i++) {
906 Visit(args->at(i));
907 CHECK_BAILOUT;
908 }
909}
910
911
912void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) {
913 // Check for inline runtime call
914 if (expr->name()->Get(0) == '_' &&
915 CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
916 BAILOUT("inlined runtime call");
917 }
918 // Check all arguments to the call. (Relies on TEMP meaning STACK.)
919 for (int i = 0; i < expr->arguments()->length(); i++) {
920 Visit(expr->arguments()->at(i));
921 CHECK_BAILOUT;
922 }
923}
924
925
926void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) {
927 switch (expr->op()) {
928 case Token::VOID:
929 case Token::NOT:
930 case Token::TYPEOF:
931 Visit(expr->expression());
932 break;
933 case Token::BIT_NOT:
934 BAILOUT("UnaryOperataion: BIT_NOT");
935 case Token::DELETE:
936 BAILOUT("UnaryOperataion: DELETE");
937 default:
938 BAILOUT("UnaryOperataion");
939 }
940}
941
942
943void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
944 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
945 Property* prop = expr->expression()->AsProperty();
946 ASSERT(var == NULL || prop == NULL);
947 if (var != NULL) {
948 // All global variables are supported.
949 if (!var->is_global()) {
950 ASSERT(var->slot() != NULL);
951 Slot::Type type = var->slot()->type();
952 if (type == Slot::LOOKUP) {
953 BAILOUT("CountOperation with lookup slot");
954 }
955 }
956 } else if (prop != NULL) {
957 Visit(prop->obj());
958 CHECK_BAILOUT;
959 Visit(prop->key());
960 CHECK_BAILOUT;
961 } else {
962 // This is a throw reference error.
963 BAILOUT("CountOperation non-variable/non-property expression");
964 }
965}
966
967
968void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
969 Visit(expr->left());
970 CHECK_BAILOUT;
971 Visit(expr->right());
972}
973
974
975void CodeGenSelector::VisitCompareOperation(CompareOperation* expr) {
976 Visit(expr->left());
977 CHECK_BAILOUT;
978 Visit(expr->right());
979}
980
981
982void CodeGenSelector::VisitThisFunction(ThisFunction* expr) {}
983
984#undef BAILOUT
985#undef CHECK_BAILOUT
986
987
Steve Blocka7e24c12009-10-30 11:49:00 +0000988} } // namespace v8::internal