OLD | NEW |
| (Empty) |
1 // Copyright 2010 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 "codegen-inl.h" | |
31 #include "data-flow.h" | |
32 #include "fast-codegen.h" | |
33 #include "scopes.h" | |
34 | |
35 namespace v8 { | |
36 namespace internal { | |
37 | |
38 #define BAILOUT(reason) \ | |
39 do { \ | |
40 if (FLAG_trace_bailout) { \ | |
41 PrintF("%s\n", reason); \ | |
42 } \ | |
43 has_supported_syntax_ = false; \ | |
44 return; \ | |
45 } while (false) | |
46 | |
47 | |
48 #define CHECK_BAILOUT \ | |
49 do { \ | |
50 if (!has_supported_syntax_) return; \ | |
51 } while (false) | |
52 | |
53 | |
54 void FastCodeGenSyntaxChecker::Check(CompilationInfo* info) { | |
55 info_ = info; | |
56 | |
57 // We do not specialize if we do not have a receiver or if it is not a | |
58 // JS object with fast mode properties. | |
59 if (!info->has_receiver()) BAILOUT("No receiver"); | |
60 if (!info->receiver()->IsJSObject()) BAILOUT("Receiver is not an object"); | |
61 Handle<JSObject> object = Handle<JSObject>::cast(info->receiver()); | |
62 if (!object->HasFastProperties()) BAILOUT("Receiver is in dictionary mode"); | |
63 | |
64 // We do not support stack or heap slots (both of which require | |
65 // allocation). | |
66 Scope* scope = info->scope(); | |
67 if (scope->num_stack_slots() > 0) { | |
68 BAILOUT("Function has stack-allocated locals"); | |
69 } | |
70 if (scope->num_heap_slots() > 0) { | |
71 BAILOUT("Function has context-allocated locals"); | |
72 } | |
73 | |
74 VisitDeclarations(scope->declarations()); | |
75 CHECK_BAILOUT; | |
76 | |
77 // We do not support empty function bodies. | |
78 if (info->function()->body()->is_empty()) { | |
79 BAILOUT("Function has an empty body"); | |
80 } | |
81 VisitStatements(info->function()->body()); | |
82 } | |
83 | |
84 | |
85 void FastCodeGenSyntaxChecker::VisitDeclarations( | |
86 ZoneList<Declaration*>* decls) { | |
87 if (!decls->is_empty()) BAILOUT("Function has declarations"); | |
88 } | |
89 | |
90 | |
91 void FastCodeGenSyntaxChecker::VisitStatements(ZoneList<Statement*>* stmts) { | |
92 if (stmts->length() != 1) { | |
93 BAILOUT("Function body is not a singleton statement."); | |
94 } | |
95 Visit(stmts->at(0)); | |
96 } | |
97 | |
98 | |
99 void FastCodeGenSyntaxChecker::VisitDeclaration(Declaration* decl) { | |
100 UNREACHABLE(); | |
101 } | |
102 | |
103 | |
104 void FastCodeGenSyntaxChecker::VisitBlock(Block* stmt) { | |
105 VisitStatements(stmt->statements()); | |
106 } | |
107 | |
108 | |
109 void FastCodeGenSyntaxChecker::VisitExpressionStatement( | |
110 ExpressionStatement* stmt) { | |
111 Visit(stmt->expression()); | |
112 } | |
113 | |
114 | |
115 void FastCodeGenSyntaxChecker::VisitEmptyStatement(EmptyStatement* stmt) { | |
116 // Supported. | |
117 } | |
118 | |
119 | |
120 void FastCodeGenSyntaxChecker::VisitIfStatement(IfStatement* stmt) { | |
121 BAILOUT("IfStatement"); | |
122 } | |
123 | |
124 | |
125 void FastCodeGenSyntaxChecker::VisitContinueStatement(ContinueStatement* stmt) { | |
126 BAILOUT("Continuestatement"); | |
127 } | |
128 | |
129 | |
130 void FastCodeGenSyntaxChecker::VisitBreakStatement(BreakStatement* stmt) { | |
131 BAILOUT("BreakStatement"); | |
132 } | |
133 | |
134 | |
135 void FastCodeGenSyntaxChecker::VisitReturnStatement(ReturnStatement* stmt) { | |
136 BAILOUT("ReturnStatement"); | |
137 } | |
138 | |
139 | |
140 void FastCodeGenSyntaxChecker::VisitWithEnterStatement( | |
141 WithEnterStatement* stmt) { | |
142 BAILOUT("WithEnterStatement"); | |
143 } | |
144 | |
145 | |
146 void FastCodeGenSyntaxChecker::VisitWithExitStatement(WithExitStatement* stmt) { | |
147 BAILOUT("WithExitStatement"); | |
148 } | |
149 | |
150 | |
151 void FastCodeGenSyntaxChecker::VisitSwitchStatement(SwitchStatement* stmt) { | |
152 BAILOUT("SwitchStatement"); | |
153 } | |
154 | |
155 | |
156 void FastCodeGenSyntaxChecker::VisitDoWhileStatement(DoWhileStatement* stmt) { | |
157 BAILOUT("DoWhileStatement"); | |
158 } | |
159 | |
160 | |
161 void FastCodeGenSyntaxChecker::VisitWhileStatement(WhileStatement* stmt) { | |
162 BAILOUT("WhileStatement"); | |
163 } | |
164 | |
165 | |
166 void FastCodeGenSyntaxChecker::VisitForStatement(ForStatement* stmt) { | |
167 BAILOUT("ForStatement"); | |
168 } | |
169 | |
170 | |
171 void FastCodeGenSyntaxChecker::VisitForInStatement(ForInStatement* stmt) { | |
172 BAILOUT("ForInStatement"); | |
173 } | |
174 | |
175 | |
176 void FastCodeGenSyntaxChecker::VisitTryCatchStatement(TryCatchStatement* stmt) { | |
177 BAILOUT("TryCatchStatement"); | |
178 } | |
179 | |
180 | |
181 void FastCodeGenSyntaxChecker::VisitTryFinallyStatement( | |
182 TryFinallyStatement* stmt) { | |
183 BAILOUT("TryFinallyStatement"); | |
184 } | |
185 | |
186 | |
187 void FastCodeGenSyntaxChecker::VisitDebuggerStatement( | |
188 DebuggerStatement* stmt) { | |
189 BAILOUT("DebuggerStatement"); | |
190 } | |
191 | |
192 | |
193 void FastCodeGenSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) { | |
194 BAILOUT("FunctionLiteral"); | |
195 } | |
196 | |
197 | |
198 void FastCodeGenSyntaxChecker::VisitSharedFunctionInfoLiteral( | |
199 SharedFunctionInfoLiteral* expr) { | |
200 BAILOUT("SharedFunctionInfoLiteral"); | |
201 } | |
202 | |
203 | |
204 void FastCodeGenSyntaxChecker::VisitConditional(Conditional* expr) { | |
205 BAILOUT("Conditional"); | |
206 } | |
207 | |
208 | |
209 void FastCodeGenSyntaxChecker::VisitSlot(Slot* expr) { | |
210 UNREACHABLE(); | |
211 } | |
212 | |
213 | |
214 void FastCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) { | |
215 // Only global variable references are supported. | |
216 Variable* var = expr->var(); | |
217 if (!var->is_global() || var->is_this()) BAILOUT("Non-global variable"); | |
218 | |
219 // Check if the global variable is existing and non-deletable. | |
220 if (info()->has_global_object()) { | |
221 LookupResult lookup; | |
222 info()->global_object()->Lookup(*expr->name(), &lookup); | |
223 if (!lookup.IsProperty()) { | |
224 BAILOUT("Non-existing global variable"); | |
225 } | |
226 // We do not handle global variables with accessors or interceptors. | |
227 if (lookup.type() != NORMAL) { | |
228 BAILOUT("Global variable with accessors or interceptors."); | |
229 } | |
230 // We do not handle deletable global variables. | |
231 if (!lookup.IsDontDelete()) { | |
232 BAILOUT("Deletable global variable"); | |
233 } | |
234 } | |
235 } | |
236 | |
237 | |
238 void FastCodeGenSyntaxChecker::VisitLiteral(Literal* expr) { | |
239 BAILOUT("Literal"); | |
240 } | |
241 | |
242 | |
243 void FastCodeGenSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) { | |
244 BAILOUT("RegExpLiteral"); | |
245 } | |
246 | |
247 | |
248 void FastCodeGenSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) { | |
249 BAILOUT("ObjectLiteral"); | |
250 } | |
251 | |
252 | |
253 void FastCodeGenSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) { | |
254 BAILOUT("ArrayLiteral"); | |
255 } | |
256 | |
257 | |
258 void FastCodeGenSyntaxChecker::VisitCatchExtensionObject( | |
259 CatchExtensionObject* expr) { | |
260 BAILOUT("CatchExtensionObject"); | |
261 } | |
262 | |
263 | |
264 void FastCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) { | |
265 // Simple assignments to (named) this properties are supported. | |
266 if (expr->op() != Token::ASSIGN) BAILOUT("Non-simple assignment"); | |
267 | |
268 Property* prop = expr->target()->AsProperty(); | |
269 if (prop == NULL) BAILOUT("Non-property assignment"); | |
270 VariableProxy* proxy = prop->obj()->AsVariableProxy(); | |
271 if (proxy == NULL || !proxy->var()->is_this()) { | |
272 BAILOUT("Non-this-property assignment"); | |
273 } | |
274 if (!prop->key()->IsPropertyName()) { | |
275 BAILOUT("Non-named-property assignment"); | |
276 } | |
277 | |
278 // We will only specialize for fields on the object itself. | |
279 // Expression::IsPropertyName implies that the name is a literal | |
280 // symbol but we do not assume that. | |
281 Literal* key = prop->key()->AsLiteral(); | |
282 if (key != NULL && key->handle()->IsString()) { | |
283 Handle<Object> receiver = info()->receiver(); | |
284 Handle<String> name = Handle<String>::cast(key->handle()); | |
285 LookupResult lookup; | |
286 receiver->Lookup(*name, &lookup); | |
287 if (!lookup.IsProperty()) { | |
288 BAILOUT("Assigned property not found at compile time"); | |
289 } | |
290 if (lookup.holder() != *receiver) BAILOUT("Non-own property assignment"); | |
291 if (!lookup.type() == FIELD) BAILOUT("Non-field property assignment"); | |
292 } else { | |
293 UNREACHABLE(); | |
294 BAILOUT("Unexpected non-string-literal property key"); | |
295 } | |
296 | |
297 Visit(expr->value()); | |
298 } | |
299 | |
300 | |
301 void FastCodeGenSyntaxChecker::VisitThrow(Throw* expr) { | |
302 BAILOUT("Throw"); | |
303 } | |
304 | |
305 | |
306 void FastCodeGenSyntaxChecker::VisitProperty(Property* expr) { | |
307 // We support named this property references. | |
308 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | |
309 if (proxy == NULL || !proxy->var()->is_this()) { | |
310 BAILOUT("Non-this-property reference"); | |
311 } | |
312 if (!expr->key()->IsPropertyName()) { | |
313 BAILOUT("Non-named-property reference"); | |
314 } | |
315 | |
316 // We will only specialize for fields on the object itself. | |
317 // Expression::IsPropertyName implies that the name is a literal | |
318 // symbol but we do not assume that. | |
319 Literal* key = expr->key()->AsLiteral(); | |
320 if (key != NULL && key->handle()->IsString()) { | |
321 Handle<Object> receiver = info()->receiver(); | |
322 Handle<String> name = Handle<String>::cast(key->handle()); | |
323 LookupResult lookup; | |
324 receiver->Lookup(*name, &lookup); | |
325 if (!lookup.IsProperty()) { | |
326 BAILOUT("Referenced property not found at compile time"); | |
327 } | |
328 if (lookup.holder() != *receiver) BAILOUT("Non-own property reference"); | |
329 if (!lookup.type() == FIELD) BAILOUT("Non-field property reference"); | |
330 } else { | |
331 UNREACHABLE(); | |
332 BAILOUT("Unexpected non-string-literal property key"); | |
333 } | |
334 } | |
335 | |
336 | |
337 void FastCodeGenSyntaxChecker::VisitCall(Call* expr) { | |
338 BAILOUT("Call"); | |
339 } | |
340 | |
341 | |
342 void FastCodeGenSyntaxChecker::VisitCallNew(CallNew* expr) { | |
343 BAILOUT("CallNew"); | |
344 } | |
345 | |
346 | |
347 void FastCodeGenSyntaxChecker::VisitCallRuntime(CallRuntime* expr) { | |
348 BAILOUT("CallRuntime"); | |
349 } | |
350 | |
351 | |
352 void FastCodeGenSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) { | |
353 BAILOUT("UnaryOperation"); | |
354 } | |
355 | |
356 | |
357 void FastCodeGenSyntaxChecker::VisitCountOperation(CountOperation* expr) { | |
358 BAILOUT("CountOperation"); | |
359 } | |
360 | |
361 | |
362 void FastCodeGenSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) { | |
363 // We support bitwise OR. | |
364 switch (expr->op()) { | |
365 case Token::COMMA: | |
366 BAILOUT("BinaryOperation COMMA"); | |
367 case Token::OR: | |
368 BAILOUT("BinaryOperation OR"); | |
369 case Token::AND: | |
370 BAILOUT("BinaryOperation AND"); | |
371 | |
372 case Token::BIT_OR: | |
373 // We support expressions nested on the left because they only require | |
374 // a pair of registers to keep all intermediate values in registers | |
375 // (i.e., the expression stack has height no more than two). | |
376 if (!expr->right()->IsLeaf()) BAILOUT("expression nested on right"); | |
377 | |
378 // We do not allow subexpressions with side effects because we | |
379 // (currently) bail out to the beginning of the full function. The | |
380 // only expressions with side effects that we would otherwise handle | |
381 // are assignments. | |
382 if (expr->left()->AsAssignment() != NULL || | |
383 expr->right()->AsAssignment() != NULL) { | |
384 BAILOUT("subexpression of binary operation has side effects"); | |
385 } | |
386 | |
387 Visit(expr->left()); | |
388 CHECK_BAILOUT; | |
389 Visit(expr->right()); | |
390 break; | |
391 | |
392 case Token::BIT_XOR: | |
393 BAILOUT("BinaryOperation BIT_XOR"); | |
394 case Token::BIT_AND: | |
395 BAILOUT("BinaryOperation BIT_AND"); | |
396 case Token::SHL: | |
397 BAILOUT("BinaryOperation SHL"); | |
398 case Token::SAR: | |
399 BAILOUT("BinaryOperation SAR"); | |
400 case Token::SHR: | |
401 BAILOUT("BinaryOperation SHR"); | |
402 case Token::ADD: | |
403 BAILOUT("BinaryOperation ADD"); | |
404 case Token::SUB: | |
405 BAILOUT("BinaryOperation SUB"); | |
406 case Token::MUL: | |
407 BAILOUT("BinaryOperation MUL"); | |
408 case Token::DIV: | |
409 BAILOUT("BinaryOperation DIV"); | |
410 case Token::MOD: | |
411 BAILOUT("BinaryOperation MOD"); | |
412 default: | |
413 UNREACHABLE(); | |
414 } | |
415 } | |
416 | |
417 | |
418 void FastCodeGenSyntaxChecker::VisitCompareOperation(CompareOperation* expr) { | |
419 BAILOUT("CompareOperation"); | |
420 } | |
421 | |
422 | |
423 void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) { | |
424 BAILOUT("ThisFunction"); | |
425 } | |
426 | |
427 #undef BAILOUT | |
428 #undef CHECK_BAILOUT | |
429 | |
430 | |
431 #define __ ACCESS_MASM(masm()) | |
432 | |
433 Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) { | |
434 // Label the AST before calling MakeCodePrologue, so AST node numbers are | |
435 // printed with the AST. | |
436 AstLabeler labeler; | |
437 labeler.Label(info); | |
438 | |
439 CodeGenerator::MakeCodePrologue(info); | |
440 | |
441 const int kInitialBufferSize = 4 * KB; | |
442 MacroAssembler masm(NULL, kInitialBufferSize); | |
443 | |
444 // Generate the fast-path code. | |
445 FastCodeGenerator fast_cgen(&masm); | |
446 fast_cgen.Generate(info); | |
447 if (fast_cgen.HasStackOverflow()) { | |
448 ASSERT(!Top::has_pending_exception()); | |
449 return Handle<Code>::null(); | |
450 } | |
451 | |
452 // Generate the full code for the function in bailout mode, using the same | |
453 // macro assembler. | |
454 CodeGenerator cgen(&masm); | |
455 CodeGeneratorScope scope(&cgen); | |
456 info->set_mode(CompilationInfo::SECONDARY); | |
457 cgen.Generate(info); | |
458 if (cgen.HasStackOverflow()) { | |
459 ASSERT(!Top::has_pending_exception()); | |
460 return Handle<Code>::null(); | |
461 } | |
462 | |
463 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP); | |
464 return CodeGenerator::MakeCodeEpilogue(&masm, flags, info); | |
465 } | |
466 | |
467 | |
468 void FastCodeGenerator::VisitDeclaration(Declaration* decl) { | |
469 UNREACHABLE(); | |
470 } | |
471 | |
472 | |
473 void FastCodeGenerator::VisitBlock(Block* stmt) { | |
474 VisitStatements(stmt->statements()); | |
475 } | |
476 | |
477 | |
478 void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { | |
479 Visit(stmt->expression()); | |
480 } | |
481 | |
482 | |
483 void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { | |
484 // Nothing to do. | |
485 } | |
486 | |
487 | |
488 void FastCodeGenerator::VisitIfStatement(IfStatement* stmt) { | |
489 UNREACHABLE(); | |
490 } | |
491 | |
492 | |
493 void FastCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { | |
494 UNREACHABLE(); | |
495 } | |
496 | |
497 | |
498 void FastCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { | |
499 UNREACHABLE(); | |
500 } | |
501 | |
502 | |
503 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | |
504 UNREACHABLE(); | |
505 } | |
506 | |
507 | |
508 void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) { | |
509 UNREACHABLE(); | |
510 } | |
511 | |
512 | |
513 void FastCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) { | |
514 UNREACHABLE(); | |
515 } | |
516 | |
517 | |
518 void FastCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | |
519 UNREACHABLE(); | |
520 } | |
521 | |
522 | |
523 void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { | |
524 UNREACHABLE(); | |
525 } | |
526 | |
527 | |
528 void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { | |
529 UNREACHABLE(); | |
530 } | |
531 | |
532 | |
533 void FastCodeGenerator::VisitForStatement(ForStatement* stmt) { | |
534 UNREACHABLE(); | |
535 } | |
536 | |
537 | |
538 void FastCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | |
539 UNREACHABLE(); | |
540 } | |
541 | |
542 | |
543 void FastCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { | |
544 UNREACHABLE(); | |
545 } | |
546 | |
547 | |
548 void FastCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | |
549 UNREACHABLE(); | |
550 } | |
551 | |
552 | |
553 void FastCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { | |
554 UNREACHABLE(); | |
555 } | |
556 | |
557 | |
558 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | |
559 UNREACHABLE(); | |
560 } | |
561 | |
562 | |
563 void FastCodeGenerator::VisitSharedFunctionInfoLiteral( | |
564 SharedFunctionInfoLiteral* expr) { | |
565 UNREACHABLE(); | |
566 } | |
567 | |
568 | |
569 void FastCodeGenerator::VisitConditional(Conditional* expr) { | |
570 UNREACHABLE(); | |
571 } | |
572 | |
573 | |
574 void FastCodeGenerator::VisitSlot(Slot* expr) { | |
575 UNREACHABLE(); | |
576 } | |
577 | |
578 | |
579 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | |
580 ASSERT(expr->var()->is_global() && !expr->var()->is_this()); | |
581 // Check if we can compile a global variable load directly from the cell. | |
582 ASSERT(info()->has_global_object()); | |
583 LookupResult lookup; | |
584 info()->global_object()->Lookup(*expr->name(), &lookup); | |
585 // We only support normal (non-accessor/interceptor) DontDelete properties | |
586 // for now. | |
587 ASSERT(lookup.IsProperty()); | |
588 ASSERT_EQ(NORMAL, lookup.type()); | |
589 ASSERT(lookup.IsDontDelete()); | |
590 Handle<Object> cell(info()->global_object()->GetPropertyCell(&lookup)); | |
591 | |
592 // Global variable lookups do not have side effects, so we do not need to | |
593 // emit code if we are in an effect context. | |
594 if (!destination().is(no_reg)) { | |
595 Comment cmnt(masm(), ";; Global"); | |
596 if (FLAG_print_ir) { | |
597 SmartPointer<char> name = expr->name()->ToCString(); | |
598 PrintF("%d: t%d = Global(%s)\n", expr->num(), | |
599 expr->num(), *name); | |
600 } | |
601 EmitGlobalVariableLoad(cell); | |
602 } | |
603 } | |
604 | |
605 | |
606 void FastCodeGenerator::VisitLiteral(Literal* expr) { | |
607 UNREACHABLE(); | |
608 } | |
609 | |
610 | |
611 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | |
612 UNREACHABLE(); | |
613 } | |
614 | |
615 | |
616 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | |
617 UNREACHABLE(); | |
618 } | |
619 | |
620 | |
621 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | |
622 UNREACHABLE(); | |
623 } | |
624 | |
625 | |
626 void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) { | |
627 UNREACHABLE(); | |
628 } | |
629 | |
630 | |
631 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | |
632 // Known to be a simple this property assignment. Effectively a unary | |
633 // operation. | |
634 { Register my_destination = destination(); | |
635 set_destination(accumulator0()); | |
636 Visit(expr->value()); | |
637 set_destination(my_destination); | |
638 } | |
639 | |
640 Property* prop = expr->target()->AsProperty(); | |
641 ASSERT_NOT_NULL(prop); | |
642 ASSERT_NOT_NULL(prop->obj()->AsVariableProxy()); | |
643 ASSERT(prop->obj()->AsVariableProxy()->var()->is_this()); | |
644 ASSERT(prop->key()->IsPropertyName()); | |
645 Handle<String> name = | |
646 Handle<String>::cast(prop->key()->AsLiteral()->handle()); | |
647 | |
648 Comment cmnt(masm(), ";; Store to this"); | |
649 if (FLAG_print_ir) { | |
650 SmartPointer<char> name_string = name->ToCString(); | |
651 PrintF("%d: ", expr->num()); | |
652 if (!destination().is(no_reg)) PrintF("t%d = ", expr->num()); | |
653 PrintF("Store(this, \"%s\", t%d)\n", *name_string, | |
654 expr->value()->num()); | |
655 } | |
656 | |
657 EmitThisPropertyStore(name); | |
658 } | |
659 | |
660 | |
661 void FastCodeGenerator::VisitThrow(Throw* expr) { | |
662 UNREACHABLE(); | |
663 } | |
664 | |
665 | |
666 void FastCodeGenerator::VisitProperty(Property* expr) { | |
667 ASSERT_NOT_NULL(expr->obj()->AsVariableProxy()); | |
668 ASSERT(expr->obj()->AsVariableProxy()->var()->is_this()); | |
669 ASSERT(expr->key()->IsPropertyName()); | |
670 if (!destination().is(no_reg)) { | |
671 Handle<String> name = | |
672 Handle<String>::cast(expr->key()->AsLiteral()->handle()); | |
673 | |
674 Comment cmnt(masm(), ";; Load from this"); | |
675 if (FLAG_print_ir) { | |
676 SmartPointer<char> name_string = name->ToCString(); | |
677 PrintF("%d: t%d = Load(this, \"%s\")\n", | |
678 expr->num(), expr->num(), *name_string); | |
679 } | |
680 EmitThisPropertyLoad(name); | |
681 } | |
682 } | |
683 | |
684 | |
685 void FastCodeGenerator::VisitCall(Call* expr) { | |
686 UNREACHABLE(); | |
687 } | |
688 | |
689 | |
690 void FastCodeGenerator::VisitCallNew(CallNew* expr) { | |
691 UNREACHABLE(); | |
692 } | |
693 | |
694 | |
695 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | |
696 UNREACHABLE(); | |
697 } | |
698 | |
699 | |
700 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | |
701 UNREACHABLE(); | |
702 } | |
703 | |
704 | |
705 void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { | |
706 UNREACHABLE(); | |
707 } | |
708 | |
709 | |
710 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | |
711 // We support limited binary operations: bitwise OR only allowed to be | |
712 // nested on the left. | |
713 ASSERT(expr->op() == Token::BIT_OR); | |
714 ASSERT(expr->right()->IsLeaf()); | |
715 | |
716 { Register my_destination = destination(); | |
717 set_destination(accumulator1()); | |
718 Visit(expr->left()); | |
719 set_destination(accumulator0()); | |
720 Visit(expr->right()); | |
721 set_destination(my_destination); | |
722 } | |
723 | |
724 Comment cmnt(masm(), ";; BIT_OR"); | |
725 if (FLAG_print_ir) { | |
726 PrintF("%d: ", expr->num()); | |
727 if (!destination().is(no_reg)) PrintF("t%d = ", expr->num()); | |
728 PrintF("BIT_OR(t%d, t%d)\n", expr->left()->num(), expr->right()->num()); | |
729 } | |
730 EmitBitOr(); | |
731 } | |
732 | |
733 | |
734 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | |
735 UNREACHABLE(); | |
736 } | |
737 | |
738 | |
739 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { | |
740 UNREACHABLE(); | |
741 } | |
742 | |
743 #undef __ | |
744 | |
745 | |
746 } } // namespace v8::internal | |
OLD | NEW |