blob: e422bf7960852132faef37263ec94f5b7b1f7336 [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
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,
71 bool is_eval) {
72 ASSERT(literal != NULL);
73
74 // Rewrite the AST by introducing .result assignments where needed.
75 if (!Rewriter::Process(literal) || !AnalyzeVariableUsage(literal)) {
76 // Signal a stack overflow by returning a null handle. The stack
77 // overflow exception will be thrown by the caller.
78 return Handle<Code>::null();
79 }
80
81 {
82 // Compute top scope and allocate variables. For lazy compilation
83 // the top scope only contains the single lazily compiled function,
84 // so this doesn't re-allocate variables repeatedly.
85 HistogramTimerScope timer(&Counters::variable_allocation);
86 Scope* top = literal->scope();
87 while (top->outer_scope() != NULL) top = top->outer_scope();
88 top->AllocateVariables(context);
89 }
90
91#ifdef DEBUG
92 if (Bootstrapper::IsActive() ?
93 FLAG_print_builtin_scopes :
94 FLAG_print_scopes) {
95 literal->scope()->Print();
96 }
97#endif
98
99 // Optimize the AST.
100 if (!Rewriter::Optimize(literal)) {
101 // Signal a stack overflow by returning a null handle. The stack
102 // overflow exception will be thrown by the caller.
103 return Handle<Code>::null();
104 }
105
106 // Generate code and return it.
Steve Block3ce2e202009-11-05 08:53:23 +0000107 if (FLAG_fast_compiler) {
108 CodeGenSelector selector;
109 CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
110 if (code_gen == CodeGenSelector::FAST) {
111 return FastCodeGenerator::MakeCode(literal, script, is_eval);
112 }
113 ASSERT(code_gen == CodeGenSelector::NORMAL);
114 }
115 return CodeGenerator::MakeCode(literal, script, is_eval);
Steve Blocka7e24c12009-10-30 11:49:00 +0000116}
117
118
119static bool IsValidJSON(FunctionLiteral* lit) {
120 if (lit->body()->length() != 1)
121 return false;
122 Statement* stmt = lit->body()->at(0);
123 if (stmt->AsExpressionStatement() == NULL)
124 return false;
125 Expression* expr = stmt->AsExpressionStatement()->expression();
126 return expr->IsValidJSON();
127}
128
129
130static Handle<JSFunction> MakeFunction(bool is_global,
131 bool is_eval,
132 Compiler::ValidationState validate,
133 Handle<Script> script,
134 Handle<Context> context,
135 v8::Extension* extension,
136 ScriptDataImpl* pre_data) {
137 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
138
139 PostponeInterruptsScope postpone;
140
141 ASSERT(!i::Top::global_context().is_null());
142 script->set_context_data((*i::Top::global_context())->data());
143
144#ifdef ENABLE_DEBUGGER_SUPPORT
145 bool is_json = (validate == Compiler::VALIDATE_JSON);
146 if (is_eval || is_json) {
147 script->set_compilation_type(
148 is_json ? Smi::FromInt(Script::COMPILATION_TYPE_JSON) :
149 Smi::FromInt(Script::COMPILATION_TYPE_EVAL));
150 // For eval scripts add information on the function from which eval was
151 // called.
152 if (is_eval) {
153 JavaScriptFrameIterator it;
154 script->set_eval_from_function(it.frame()->function());
155 int offset = it.frame()->pc() - it.frame()->code()->instruction_start();
156 script->set_eval_from_instructions_offset(Smi::FromInt(offset));
157 }
158 }
159
160 // Notify debugger
161 Debugger::OnBeforeCompile(script);
162#endif
163
164 // Only allow non-global compiles for eval.
165 ASSERT(is_eval || is_global);
166
167 // Build AST.
168 FunctionLiteral* lit = MakeAST(is_global, script, extension, pre_data);
169
170 // Check for parse errors.
171 if (lit == NULL) {
172 ASSERT(Top::has_pending_exception());
173 return Handle<JSFunction>::null();
174 }
175
176 // When parsing JSON we do an ordinary parse and then afterwards
177 // check the AST to ensure it was well-formed. If not we give a
178 // syntax error.
179 if (validate == Compiler::VALIDATE_JSON && !IsValidJSON(lit)) {
180 HandleScope scope;
181 Handle<JSArray> args = Factory::NewJSArray(1);
182 Handle<Object> source(script->source());
183 SetElement(args, 0, source);
184 Handle<Object> result = Factory::NewSyntaxError("invalid_json", args);
185 Top::Throw(*result, NULL);
186 return Handle<JSFunction>::null();
187 }
188
189 // Measure how long it takes to do the compilation; only take the
190 // rest of the function into account to avoid overlap with the
191 // parsing statistics.
192 HistogramTimer* rate = is_eval
193 ? &Counters::compile_eval
194 : &Counters::compile;
195 HistogramTimerScope timer(rate);
196
197 // Compile the code.
198 Handle<Code> code = MakeCode(lit, script, context, is_eval);
199
200 // Check for stack-overflow exceptions.
201 if (code.is_null()) {
202 Top::StackOverflow();
203 return Handle<JSFunction>::null();
204 }
205
206#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
207 // Log the code generation for the script. Check explicit whether logging is
208 // to avoid allocating when not required.
209 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
210 if (script->name()->IsString()) {
211 SmartPointer<char> data =
212 String::cast(script->name())->ToCString(DISALLOW_NULLS);
213 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
214 *code, *data));
215 OProfileAgent::CreateNativeCodeRegion(*data,
216 code->instruction_start(),
217 code->instruction_size());
218 } else {
219 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
220 *code, ""));
221 OProfileAgent::CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
222 code->instruction_start(),
223 code->instruction_size());
224 }
225 }
226#endif
227
228 // Allocate function.
229 Handle<JSFunction> fun =
230 Factory::NewFunctionBoilerplate(lit->name(),
231 lit->materialized_literal_count(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 code);
233
234 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
235 CodeGenerator::SetFunctionInfo(fun, lit, true, script);
236
237 // Hint to the runtime system used when allocating space for initial
238 // property space by setting the expected number of properties for
239 // the instances of the function.
240 SetExpectedNofPropertiesFromEstimate(fun, lit->expected_property_count());
241
242#ifdef ENABLE_DEBUGGER_SUPPORT
243 // Notify debugger
244 Debugger::OnAfterCompile(script, fun);
245#endif
246
247 return fun;
248}
249
250
251static StaticResource<SafeStringInputBuffer> safe_string_input_buffer;
252
253
254Handle<JSFunction> Compiler::Compile(Handle<String> source,
255 Handle<Object> script_name,
256 int line_offset, int column_offset,
257 v8::Extension* extension,
258 ScriptDataImpl* input_pre_data) {
259 int source_length = source->length();
260 Counters::total_load_size.Increment(source_length);
261 Counters::total_compile_size.Increment(source_length);
262
263 // The VM is in the COMPILER state until exiting this function.
264 VMState state(COMPILER);
265
266 // Do a lookup in the compilation cache but not for extensions.
267 Handle<JSFunction> result;
268 if (extension == NULL) {
269 result = CompilationCache::LookupScript(source,
270 script_name,
271 line_offset,
272 column_offset);
273 }
274
275 if (result.is_null()) {
276 // No cache entry found. Do pre-parsing and compile the script.
277 ScriptDataImpl* pre_data = input_pre_data;
278 if (pre_data == NULL && source_length >= FLAG_min_preparse_length) {
279 Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
280 buf->Reset(source.location());
281 pre_data = PreParse(source, buf.value(), extension);
282 }
283
284 // Create a script object describing the script to be compiled.
285 Handle<Script> script = Factory::NewScript(source);
286 if (!script_name.is_null()) {
287 script->set_name(*script_name);
288 script->set_line_offset(Smi::FromInt(line_offset));
289 script->set_column_offset(Smi::FromInt(column_offset));
290 }
291
292 // Compile the function and add it to the cache.
293 result = MakeFunction(true,
294 false,
295 DONT_VALIDATE_JSON,
296 script,
297 Handle<Context>::null(),
298 extension,
299 pre_data);
300 if (extension == NULL && !result.is_null()) {
301 CompilationCache::PutScript(source, result);
302 }
303
304 // Get rid of the pre-parsing data (if necessary).
305 if (input_pre_data == NULL && pre_data != NULL) {
306 delete pre_data;
307 }
308 }
309
310 if (result.is_null()) Top::ReportPendingMessages();
311 return result;
312}
313
314
315Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
316 Handle<Context> context,
317 bool is_global,
318 ValidationState validate) {
319 // Note that if validation is required then no path through this
320 // function is allowed to return a value without validating that
321 // the input is legal json.
322
323 int source_length = source->length();
324 Counters::total_eval_size.Increment(source_length);
325 Counters::total_compile_size.Increment(source_length);
326
327 // The VM is in the COMPILER state until exiting this function.
328 VMState state(COMPILER);
329
330 // Do a lookup in the compilation cache; if the entry is not there,
331 // invoke the compiler and add the result to the cache. If we're
332 // evaluating json we bypass the cache since we can't be sure a
333 // potential value in the cache has been validated.
334 Handle<JSFunction> result;
335 if (validate == DONT_VALIDATE_JSON)
336 result = CompilationCache::LookupEval(source, context, is_global);
337
338 if (result.is_null()) {
339 // Create a script object describing the script to be compiled.
340 Handle<Script> script = Factory::NewScript(source);
341 result = MakeFunction(is_global,
342 true,
343 validate,
344 script,
345 context,
346 NULL,
347 NULL);
348 if (!result.is_null() && validate != VALIDATE_JSON) {
349 // For json it's unlikely that we'll ever see exactly the same
350 // string again so we don't use the compilation cache.
351 CompilationCache::PutEval(source, context, is_global, result);
352 }
353 }
354
355 return result;
356}
357
358
359bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
360 int loop_nesting) {
361 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
362
363 // The VM is in the COMPILER state until exiting this function.
364 VMState state(COMPILER);
365
366 PostponeInterruptsScope postpone;
367
368 // Compute name, source code and script data.
369 Handle<String> name(String::cast(shared->name()));
370 Handle<Script> script(Script::cast(shared->script()));
371
372 int start_position = shared->start_position();
373 int end_position = shared->end_position();
374 bool is_expression = shared->is_expression();
375 Counters::total_compile_size.Increment(end_position - start_position);
376
377 // Generate the AST for the lazily compiled function. The AST may be
378 // NULL in case of parser stack overflow.
379 FunctionLiteral* lit = MakeLazyAST(script, name,
380 start_position,
381 end_position,
382 is_expression);
383
384 // Check for parse errors.
385 if (lit == NULL) {
386 ASSERT(Top::has_pending_exception());
387 return false;
388 }
389
390 // Update the loop nesting in the function literal.
391 lit->set_loop_nesting(loop_nesting);
392
393 // Measure how long it takes to do the lazy compilation; only take
394 // the rest of the function into account to avoid overlap with the
395 // lazy parsing statistics.
396 HistogramTimerScope timer(&Counters::compile_lazy);
397
398 // Compile the code.
399 Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false);
400
401 // Check for stack-overflow exception.
402 if (code.is_null()) {
403 Top::StackOverflow();
404 return false;
405 }
406
407#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
408 // Log the code generation. If source information is available include script
409 // name and line number. Check explicit whether logging is enabled as finding
410 // the line number is not for free.
411 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
412 Handle<String> func_name(name->length() > 0 ?
413 *name : shared->inferred_name());
414 if (script->name()->IsString()) {
415 int line_num = GetScriptLineNumber(script, start_position) + 1;
416 LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name,
417 String::cast(script->name()), line_num));
418 OProfileAgent::CreateNativeCodeRegion(*func_name,
419 String::cast(script->name()),
420 line_num,
421 code->instruction_start(),
422 code->instruction_size());
423 } else {
424 LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name));
425 OProfileAgent::CreateNativeCodeRegion(*func_name,
426 code->instruction_start(),
427 code->instruction_size());
428 }
429 }
430#endif
431
432 // Update the shared function info with the compiled code.
433 shared->set_code(*code);
434
435 // Set the expected number of properties for instances.
436 SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
437
438 // Set the optimication hints after performing lazy compilation, as these are
439 // not set when the function is set up as a lazily compiled function.
440 shared->SetThisPropertyAssignmentsInfo(
441 lit->has_only_this_property_assignments(),
442 lit->has_only_simple_this_property_assignments(),
443 *lit->this_property_assignments());
444
445 // Check the function has compiled code.
446 ASSERT(shared->is_compiled());
447 return true;
448}
449
450
Steve Block3ce2e202009-11-05 08:53:23 +0000451CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) {
452 Scope* scope = fun->scope();
453
454 if (!scope->is_global_scope()) {
455 if (FLAG_trace_bailout) PrintF("Non-global scope\n");
456 return NORMAL;
457 }
458 ASSERT(scope->num_heap_slots() == 0);
459 ASSERT(scope->arguments() == NULL);
460
461 has_supported_syntax_ = true;
462 VisitDeclarations(fun->scope()->declarations());
463 if (!has_supported_syntax_) return NORMAL;
464
465 VisitStatements(fun->body());
466 return has_supported_syntax_ ? FAST : NORMAL;
467}
468
469
470#define BAILOUT(reason) \
471 do { \
472 if (FLAG_trace_bailout) { \
473 PrintF("%s\n", reason); \
474 } \
475 has_supported_syntax_ = false; \
476 return; \
477 } while (false)
478
479
480#define CHECK_BAILOUT \
481 do { \
482 if (!has_supported_syntax_) return; \
483 } while (false)
484
485
486void CodeGenSelector::VisitDeclarations(ZoneList<Declaration*>* decls) {
487 for (int i = 0; i < decls->length(); i++) {
488 Visit(decls->at(i));
489 CHECK_BAILOUT;
490 }
491}
492
493
494void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) {
495 for (int i = 0, len = stmts->length(); i < len; i++) {
496 Visit(stmts->at(i));
497 CHECK_BAILOUT;
498 }
499}
500
501
502void CodeGenSelector::VisitDeclaration(Declaration* decl) {
503 Variable* var = decl->proxy()->var();
504 if (!var->is_global() || var->mode() == Variable::CONST) {
505 BAILOUT("Non-global declaration");
506 }
507}
508
509
510void CodeGenSelector::VisitBlock(Block* stmt) {
511 VisitStatements(stmt->statements());
512}
513
514
515void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) {
516 Expression* expr = stmt->expression();
517 Visit(expr);
518 CHECK_BAILOUT;
519 expr->set_location(Location::Nowhere());
520}
521
522
523void CodeGenSelector::VisitEmptyStatement(EmptyStatement* stmt) {
524 // EmptyStatement is supported.
525}
526
527
528void CodeGenSelector::VisitIfStatement(IfStatement* stmt) {
529 BAILOUT("IfStatement");
530}
531
532
533void CodeGenSelector::VisitContinueStatement(ContinueStatement* stmt) {
534 BAILOUT("ContinueStatement");
535}
536
537
538void CodeGenSelector::VisitBreakStatement(BreakStatement* stmt) {
539 BAILOUT("BreakStatement");
540}
541
542
543void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) {
544 Visit(stmt->expression());
545}
546
547
548void CodeGenSelector::VisitWithEnterStatement(WithEnterStatement* stmt) {
549 BAILOUT("WithEnterStatement");
550}
551
552
553void CodeGenSelector::VisitWithExitStatement(WithExitStatement* stmt) {
554 BAILOUT("WithExitStatement");
555}
556
557
558void CodeGenSelector::VisitSwitchStatement(SwitchStatement* stmt) {
559 BAILOUT("SwitchStatement");
560}
561
562
563void CodeGenSelector::VisitDoWhileStatement(DoWhileStatement* stmt) {
564 BAILOUT("DoWhileStatement");
565}
566
567
568void CodeGenSelector::VisitWhileStatement(WhileStatement* stmt) {
569 BAILOUT("WhileStatement");
570}
571
572
573void CodeGenSelector::VisitForStatement(ForStatement* stmt) {
574 BAILOUT("ForStatement");
575}
576
577
578void CodeGenSelector::VisitForInStatement(ForInStatement* stmt) {
579 BAILOUT("ForInStatement");
580}
581
582
583void CodeGenSelector::VisitTryCatchStatement(TryCatchStatement* stmt) {
584 BAILOUT("TryCatchStatement");
585}
586
587
588void CodeGenSelector::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
589 BAILOUT("TryFinallyStatement");
590}
591
592
593void CodeGenSelector::VisitDebuggerStatement(DebuggerStatement* stmt) {
594 BAILOUT("DebuggerStatement");
595}
596
597
598void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) {
599 if (!expr->AllowsLazyCompilation()) {
600 BAILOUT("FunctionLiteral does not allow lazy compilation");
601 }
602}
603
604
605void CodeGenSelector::VisitFunctionBoilerplateLiteral(
606 FunctionBoilerplateLiteral* expr) {
607 BAILOUT("FunctionBoilerplateLiteral");
608}
609
610
611void CodeGenSelector::VisitConditional(Conditional* expr) {
612 BAILOUT("Conditional");
613}
614
615
616void CodeGenSelector::VisitSlot(Slot* expr) {
617 Slot::Type type = expr->type();
618 if (type != Slot::PARAMETER && type != Slot::LOCAL) {
619 BAILOUT("non-parameter/non-local slot reference");
620 }
621}
622
623
624void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
625 Expression* rewrite = expr->var()->rewrite();
626 if (rewrite != NULL) Visit(rewrite);
627}
628
629
630void CodeGenSelector::VisitLiteral(Literal* expr) {
631 // All literals are supported.
632 expr->set_location(Location::Constant());
633}
634
635
636void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) {
637 // RegexpLiterals are supported.
638}
639
640
641void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) {
642 BAILOUT("ObjectLiteral");
643}
644
645
646void CodeGenSelector::VisitArrayLiteral(ArrayLiteral* expr) {
647 ZoneList<Expression*>* subexprs = expr->values();
648 for (int i = 0, len = subexprs->length(); i < len; i++) {
649 Expression* subexpr = subexprs->at(i);
650 if (subexpr->AsLiteral() != NULL) continue;
651 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
652 Visit(subexpr);
653 CHECK_BAILOUT;
654 }
655}
656
657
658void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) {
659 BAILOUT("CatchExtensionObject");
660}
661
662
663void CodeGenSelector::VisitAssignment(Assignment* expr) {
664 // We support plain non-compound assignments to parameters and
665 // non-context (stack-allocated) locals.
666 if (expr->starts_initialization_block()) BAILOUT("initialization block");
667
668 Token::Value op = expr->op();
669 if (op == Token::INIT_CONST) BAILOUT("initialize constant");
670 if (op != Token::ASSIGN && op != Token::INIT_VAR) {
671 BAILOUT("compound assignment");
672 }
673
674 Variable* var = expr->target()->AsVariableProxy()->AsVariable();
675 if (var == NULL) BAILOUT("non-variable assignment");
676
677 if (!var->is_global()) {
678 ASSERT(var->slot() != NULL);
679 Slot::Type type = var->slot()->type();
680 if (type != Slot::PARAMETER && type != Slot::LOCAL) {
681 BAILOUT("non-parameter/non-local slot assignment");
682 }
683 }
684
685 Visit(expr->value());
686}
687
688
689void CodeGenSelector::VisitThrow(Throw* expr) {
690 BAILOUT("Throw");
691}
692
693
694void CodeGenSelector::VisitProperty(Property* expr) {
695 BAILOUT("Property");
696}
697
698
699void CodeGenSelector::VisitCall(Call* expr) {
700 Expression* fun = expr->expression();
701 ZoneList<Expression*>* args = expr->arguments();
702 Variable* var = fun->AsVariableProxy()->AsVariable();
703
704 // Check for supported calls
705 if (var != NULL && var->is_possibly_eval()) {
706 BAILOUT("Call to a function named 'eval'");
707 } else if (var != NULL && !var->is_this() && var->is_global()) {
708 // ----------------------------------
709 // JavaScript example: 'foo(1, 2, 3)' // foo is global
710 // ----------------------------------
711 } else {
712 BAILOUT("Call to a non-global function");
713 }
714 // Check all arguments to the call
715 for (int i = 0; i < args->length(); i++) {
716 Visit(args->at(i));
717 CHECK_BAILOUT;
718 }
719}
720
721
722void CodeGenSelector::VisitCallNew(CallNew* expr) {
723 BAILOUT("CallNew");
724}
725
726
727void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) {
728 // In case of JS runtime function bail out.
729 if (expr->function() == NULL) BAILOUT("CallRuntime");
730 // Check for inline runtime call
731 if (expr->name()->Get(0) == '_' &&
732 CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
733 BAILOUT("InlineRuntimeCall");
734 }
735 for (int i = 0; i < expr->arguments()->length(); i++) {
736 Visit(expr->arguments()->at(i));
737 CHECK_BAILOUT;
738 }
739}
740
741
742void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) {
743 BAILOUT("UnaryOperation");
744}
745
746
747void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
748 BAILOUT("CountOperation");
749}
750
751
752void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
753 switch (expr->op()) {
754 case Token::OR:
755 Visit(expr->left());
756 CHECK_BAILOUT;
757 Visit(expr->right());
758 break;
759
760 default:
761 BAILOUT("Unsupported binary operation");
762 }
763}
764
765
766void CodeGenSelector::VisitCompareOperation(CompareOperation* expr) {
767 BAILOUT("CompareOperation");
768}
769
770
771void CodeGenSelector::VisitThisFunction(ThisFunction* expr) {
772 BAILOUT("ThisFunction");
773}
774
775#undef BAILOUT
776#undef CHECK_BAILOUT
777
778
Steve Blocka7e24c12009-10-30 11:49:00 +0000779} } // namespace v8::internal