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 #if defined(V8_TARGET_ARCH_IA32) | |
31 | |
32 #include "codegen-inl.h" | |
33 #include "fast-codegen.h" | |
34 #include "data-flow.h" | |
35 #include "scopes.h" | |
36 | |
37 namespace v8 { | |
38 namespace internal { | |
39 | |
40 #define BAILOUT(reason) \ | |
41 do { \ | |
42 if (FLAG_trace_bailout) { \ | |
43 PrintF("%s\n", reason); \ | |
44 } \ | |
45 has_supported_syntax_ = false; \ | |
46 return; \ | |
47 } while (false) | |
48 | |
49 | |
50 #define CHECK_BAILOUT \ | |
51 do { \ | |
52 if (!has_supported_syntax_) return; \ | |
53 } while (false) | |
54 | |
55 | |
56 void FastCodeGenSyntaxChecker::Check(CompilationInfo* info) { | |
57 info_ = info; | |
58 | |
59 // We do not specialize if we do not have a receiver or if it is not a | |
60 // JS object with fast mode properties. | |
61 if (!info->has_receiver()) BAILOUT("No receiver"); | |
62 if (!info->receiver()->IsJSObject()) BAILOUT("Receiver is not an object"); | |
63 Handle<JSObject> object = Handle<JSObject>::cast(info->receiver()); | |
64 if (!object->HasFastProperties()) BAILOUT("Receiver is in dictionary mode"); | |
65 | |
66 // We do not support stack or heap slots (both of which require | |
67 // allocation). | |
68 Scope* scope = info->scope(); | |
69 if (scope->num_stack_slots() > 0) { | |
70 BAILOUT("Function has stack-allocated locals"); | |
71 } | |
72 if (scope->num_heap_slots() > 0) { | |
73 BAILOUT("Function has context-allocated locals"); | |
74 } | |
75 | |
76 VisitDeclarations(scope->declarations()); | |
77 CHECK_BAILOUT; | |
78 | |
79 // We do not support empty function bodies. | |
80 if (info->function()->body()->is_empty()) { | |
81 BAILOUT("Function has an empty body"); | |
82 } | |
83 VisitStatements(info->function()->body()); | |
84 } | |
85 | |
86 | |
87 void FastCodeGenSyntaxChecker::VisitDeclarations( | |
88 ZoneList<Declaration*>* decls) { | |
89 if (!decls->is_empty()) BAILOUT("Function has declarations"); | |
90 } | |
91 | |
92 | |
93 void FastCodeGenSyntaxChecker::VisitStatements(ZoneList<Statement*>* stmts) { | |
94 if (stmts->length() != 1) { | |
95 BAILOUT("Function body is not a singleton statement."); | |
96 } | |
97 Visit(stmts->at(0)); | |
98 } | |
99 | |
100 | |
101 void FastCodeGenSyntaxChecker::VisitDeclaration(Declaration* decl) { | |
102 UNREACHABLE(); | |
103 } | |
104 | |
105 | |
106 void FastCodeGenSyntaxChecker::VisitBlock(Block* stmt) { | |
107 VisitStatements(stmt->statements()); | |
108 } | |
109 | |
110 | |
111 void FastCodeGenSyntaxChecker::VisitExpressionStatement( | |
112 ExpressionStatement* stmt) { | |
113 Visit(stmt->expression()); | |
114 } | |
115 | |
116 | |
117 void FastCodeGenSyntaxChecker::VisitEmptyStatement(EmptyStatement* stmt) { | |
118 // Supported. | |
119 } | |
120 | |
121 | |
122 void FastCodeGenSyntaxChecker::VisitIfStatement(IfStatement* stmt) { | |
123 BAILOUT("IfStatement"); | |
124 } | |
125 | |
126 | |
127 void FastCodeGenSyntaxChecker::VisitContinueStatement(ContinueStatement* stmt) { | |
128 BAILOUT("Continuestatement"); | |
129 } | |
130 | |
131 | |
132 void FastCodeGenSyntaxChecker::VisitBreakStatement(BreakStatement* stmt) { | |
133 BAILOUT("BreakStatement"); | |
134 } | |
135 | |
136 | |
137 void FastCodeGenSyntaxChecker::VisitReturnStatement(ReturnStatement* stmt) { | |
138 BAILOUT("ReturnStatement"); | |
139 } | |
140 | |
141 | |
142 void FastCodeGenSyntaxChecker::VisitWithEnterStatement( | |
143 WithEnterStatement* stmt) { | |
144 BAILOUT("WithEnterStatement"); | |
145 } | |
146 | |
147 | |
148 void FastCodeGenSyntaxChecker::VisitWithExitStatement(WithExitStatement* stmt) { | |
149 BAILOUT("WithExitStatement"); | |
150 } | |
151 | |
152 | |
153 void FastCodeGenSyntaxChecker::VisitSwitchStatement(SwitchStatement* stmt) { | |
154 BAILOUT("SwitchStatement"); | |
155 } | |
156 | |
157 | |
158 void FastCodeGenSyntaxChecker::VisitDoWhileStatement(DoWhileStatement* stmt) { | |
159 BAILOUT("DoWhileStatement"); | |
160 } | |
161 | |
162 | |
163 void FastCodeGenSyntaxChecker::VisitWhileStatement(WhileStatement* stmt) { | |
164 BAILOUT("WhileStatement"); | |
165 } | |
166 | |
167 | |
168 void FastCodeGenSyntaxChecker::VisitForStatement(ForStatement* stmt) { | |
169 BAILOUT("ForStatement"); | |
170 } | |
171 | |
172 | |
173 void FastCodeGenSyntaxChecker::VisitForInStatement(ForInStatement* stmt) { | |
174 BAILOUT("ForInStatement"); | |
175 } | |
176 | |
177 | |
178 void FastCodeGenSyntaxChecker::VisitTryCatchStatement(TryCatchStatement* stmt) { | |
179 BAILOUT("TryCatchStatement"); | |
180 } | |
181 | |
182 | |
183 void FastCodeGenSyntaxChecker::VisitTryFinallyStatement( | |
184 TryFinallyStatement* stmt) { | |
185 BAILOUT("TryFinallyStatement"); | |
186 } | |
187 | |
188 | |
189 void FastCodeGenSyntaxChecker::VisitDebuggerStatement( | |
190 DebuggerStatement* stmt) { | |
191 BAILOUT("DebuggerStatement"); | |
192 } | |
193 | |
194 | |
195 void FastCodeGenSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) { | |
196 BAILOUT("FunctionLiteral"); | |
197 } | |
198 | |
199 | |
200 void FastCodeGenSyntaxChecker::VisitSharedFunctionInfoLiteral( | |
201 SharedFunctionInfoLiteral* expr) { | |
202 BAILOUT("SharedFunctionInfoLiteral"); | |
203 } | |
204 | |
205 | |
206 void FastCodeGenSyntaxChecker::VisitConditional(Conditional* expr) { | |
207 BAILOUT("Conditional"); | |
208 } | |
209 | |
210 | |
211 void FastCodeGenSyntaxChecker::VisitSlot(Slot* expr) { | |
212 UNREACHABLE(); | |
213 } | |
214 | |
215 | |
216 void FastCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) { | |
217 // Only global variable references are supported. | |
218 Variable* var = expr->var(); | |
219 if (!var->is_global() || var->is_this()) BAILOUT("Non-global variable"); | |
220 | |
221 // Check if the global variable is existing and non-deletable. | |
222 if (info()->has_global_object()) { | |
223 LookupResult lookup; | |
224 info()->global_object()->Lookup(*expr->name(), &lookup); | |
225 if (!lookup.IsProperty()) { | |
226 BAILOUT("Non-existing global variable"); | |
227 } | |
228 // We do not handle global variables with accessors or interceptors. | |
229 if (lookup.type() != NORMAL) { | |
230 BAILOUT("Global variable with accessors or interceptors."); | |
231 } | |
232 // We do not handle deletable global variables. | |
233 if (!lookup.IsDontDelete()) { | |
234 BAILOUT("Deletable global variable"); | |
235 } | |
236 } | |
237 } | |
238 | |
239 | |
240 void FastCodeGenSyntaxChecker::VisitLiteral(Literal* expr) { | |
241 BAILOUT("Literal"); | |
242 } | |
243 | |
244 | |
245 void FastCodeGenSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) { | |
246 BAILOUT("RegExpLiteral"); | |
247 } | |
248 | |
249 | |
250 void FastCodeGenSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) { | |
251 BAILOUT("ObjectLiteral"); | |
252 } | |
253 | |
254 | |
255 void FastCodeGenSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) { | |
256 BAILOUT("ArrayLiteral"); | |
257 } | |
258 | |
259 | |
260 void FastCodeGenSyntaxChecker::VisitCatchExtensionObject( | |
261 CatchExtensionObject* expr) { | |
262 BAILOUT("CatchExtensionObject"); | |
263 } | |
264 | |
265 | |
266 void FastCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) { | |
267 // Simple assignments to (named) this properties are supported. | |
268 if (expr->op() != Token::ASSIGN) BAILOUT("Non-simple assignment"); | |
269 | |
270 Property* prop = expr->target()->AsProperty(); | |
271 if (prop == NULL) BAILOUT("Non-property assignment"); | |
272 VariableProxy* proxy = prop->obj()->AsVariableProxy(); | |
273 if (proxy == NULL || !proxy->var()->is_this()) { | |
274 BAILOUT("Non-this-property assignment"); | |
275 } | |
276 if (!prop->key()->IsPropertyName()) { | |
277 BAILOUT("Non-named-property assignment"); | |
278 } | |
279 | |
280 // We will only specialize for fields on the object itself. | |
281 // Expression::IsPropertyName implies that the name is a literal | |
282 // symbol but we do not assume that. | |
283 Literal* key = prop->key()->AsLiteral(); | |
284 if (key != NULL && key->handle()->IsString()) { | |
285 Handle<Object> receiver = info()->receiver(); | |
286 Handle<String> name = Handle<String>::cast(key->handle()); | |
287 LookupResult lookup; | |
288 receiver->Lookup(*name, &lookup); | |
289 if (!lookup.IsProperty()) { | |
290 BAILOUT("Assigned property not found at compile time"); | |
291 } | |
292 if (lookup.holder() != *receiver) BAILOUT("Non-own property assignment"); | |
293 if (!lookup.type() == FIELD) BAILOUT("Non-field property assignment"); | |
294 } else { | |
295 UNREACHABLE(); | |
296 BAILOUT("Unexpected non-string-literal property key"); | |
297 } | |
298 | |
299 Visit(expr->value()); | |
300 } | |
301 | |
302 | |
303 void FastCodeGenSyntaxChecker::VisitThrow(Throw* expr) { | |
304 BAILOUT("Throw"); | |
305 } | |
306 | |
307 | |
308 void FastCodeGenSyntaxChecker::VisitProperty(Property* expr) { | |
309 // We support named this property references. | |
310 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | |
311 if (proxy == NULL || !proxy->var()->is_this()) { | |
312 BAILOUT("Non-this-property reference"); | |
313 } | |
314 if (!expr->key()->IsPropertyName()) { | |
315 BAILOUT("Non-named-property reference"); | |
316 } | |
317 | |
318 // We will only specialize for fields on the object itself. | |
319 // Expression::IsPropertyName implies that the name is a literal | |
320 // symbol but we do not assume that. | |
321 Literal* key = expr->key()->AsLiteral(); | |
322 if (key != NULL && key->handle()->IsString()) { | |
323 Handle<Object> receiver = info()->receiver(); | |
324 Handle<String> name = Handle<String>::cast(key->handle()); | |
325 LookupResult lookup; | |
326 receiver->Lookup(*name, &lookup); | |
327 if (!lookup.IsProperty()) { | |
328 BAILOUT("Referenced property not found at compile time"); | |
329 } | |
330 if (lookup.holder() != *receiver) BAILOUT("Non-own property reference"); | |
331 if (!lookup.type() == FIELD) BAILOUT("Non-field property reference"); | |
332 } else { | |
333 UNREACHABLE(); | |
334 BAILOUT("Unexpected non-string-literal property key"); | |
335 } | |
336 } | |
337 | |
338 | |
339 void FastCodeGenSyntaxChecker::VisitCall(Call* expr) { | |
340 BAILOUT("Call"); | |
341 } | |
342 | |
343 | |
344 void FastCodeGenSyntaxChecker::VisitCallNew(CallNew* expr) { | |
345 BAILOUT("CallNew"); | |
346 } | |
347 | |
348 | |
349 void FastCodeGenSyntaxChecker::VisitCallRuntime(CallRuntime* expr) { | |
350 BAILOUT("CallRuntime"); | |
351 } | |
352 | |
353 | |
354 void FastCodeGenSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) { | |
355 BAILOUT("UnaryOperation"); | |
356 } | |
357 | |
358 | |
359 void FastCodeGenSyntaxChecker::VisitCountOperation(CountOperation* expr) { | |
360 BAILOUT("CountOperation"); | |
361 } | |
362 | |
363 | |
364 void FastCodeGenSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) { | |
365 // We support bitwise OR. | |
366 switch (expr->op()) { | |
367 case Token::COMMA: | |
368 BAILOUT("BinaryOperation COMMA"); | |
369 case Token::OR: | |
370 BAILOUT("BinaryOperation OR"); | |
371 case Token::AND: | |
372 BAILOUT("BinaryOperation AND"); | |
373 | |
374 case Token::BIT_OR: | |
375 // We support expressions nested on the left because they only require | |
376 // a pair of registers to keep all intermediate values in registers | |
377 // (i.e., the expression stack has height no more than two). | |
378 if (!expr->right()->IsLeaf()) BAILOUT("expression nested on right"); | |
379 | |
380 // We do not allow subexpressions with side effects because we | |
381 // (currently) bail out to the beginning of the full function. The | |
382 // only expressions with side effects that we would otherwise handle | |
383 // are assignments. | |
384 if (expr->left()->AsAssignment() != NULL || | |
385 expr->right()->AsAssignment() != NULL) { | |
386 BAILOUT("subexpression of binary operation has side effects"); | |
387 } | |
388 | |
389 Visit(expr->left()); | |
390 CHECK_BAILOUT; | |
391 Visit(expr->right()); | |
392 break; | |
393 | |
394 case Token::BIT_XOR: | |
395 BAILOUT("BinaryOperation BIT_XOR"); | |
396 case Token::BIT_AND: | |
397 BAILOUT("BinaryOperation BIT_AND"); | |
398 case Token::SHL: | |
399 BAILOUT("BinaryOperation SHL"); | |
400 case Token::SAR: | |
401 BAILOUT("BinaryOperation SAR"); | |
402 case Token::SHR: | |
403 BAILOUT("BinaryOperation SHR"); | |
404 case Token::ADD: | |
405 BAILOUT("BinaryOperation ADD"); | |
406 case Token::SUB: | |
407 BAILOUT("BinaryOperation SUB"); | |
408 case Token::MUL: | |
409 BAILOUT("BinaryOperation MUL"); | |
410 case Token::DIV: | |
411 BAILOUT("BinaryOperation DIV"); | |
412 case Token::MOD: | |
413 BAILOUT("BinaryOperation MOD"); | |
414 default: | |
415 UNREACHABLE(); | |
416 } | |
417 } | |
418 | |
419 | |
420 void FastCodeGenSyntaxChecker::VisitCompareOperation(CompareOperation* expr) { | |
421 BAILOUT("CompareOperation"); | |
422 } | |
423 | |
424 | |
425 void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) { | |
426 BAILOUT("ThisFunction"); | |
427 } | |
428 | |
429 #undef BAILOUT | |
430 #undef CHECK_BAILOUT | |
431 | |
432 | |
433 #define __ ACCESS_MASM(masm()) | |
434 | |
435 Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) { | |
436 // Label the AST before calling MakeCodePrologue, so AST node numbers are | |
437 // printed with the AST. | |
438 AstLabeler labeler; | |
439 labeler.Label(info); | |
440 | |
441 CodeGenerator::MakeCodePrologue(info); | |
442 | |
443 const int kInitialBufferSize = 4 * KB; | |
444 MacroAssembler masm(NULL, kInitialBufferSize); | |
445 | |
446 // Generate the fast-path code. | |
447 FastCodeGenerator fast_cgen(&masm); | |
448 fast_cgen.Generate(info); | |
449 if (fast_cgen.HasStackOverflow()) { | |
450 ASSERT(!Top::has_pending_exception()); | |
451 return Handle<Code>::null(); | |
452 } | |
453 | |
454 // Generate the full code for the function in bailout mode, using the same | |
455 // macro assembler. | |
456 CodeGenerator cgen(&masm); | |
457 CodeGeneratorScope scope(&cgen); | |
458 info->set_mode(CompilationInfo::SECONDARY); | |
459 cgen.Generate(info); | |
460 if (cgen.HasStackOverflow()) { | |
461 ASSERT(!Top::has_pending_exception()); | |
462 return Handle<Code>::null(); | |
463 } | |
464 | |
465 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP); | |
466 return CodeGenerator::MakeCodeEpilogue(&masm, flags, info); | |
467 } | |
468 | |
469 | |
470 Register FastCodeGenerator::accumulator0() { return eax; } | |
471 Register FastCodeGenerator::accumulator1() { return edx; } | |
472 Register FastCodeGenerator::scratch0() { return ecx; } | |
473 Register FastCodeGenerator::scratch1() { return edi; } | |
474 Register FastCodeGenerator::receiver_reg() { return ebx; } | |
475 Register FastCodeGenerator::context_reg() { return esi; } | |
476 | |
477 | |
478 void FastCodeGenerator::EmitLoadReceiver() { | |
479 // Offset 2 is due to return address and saved frame pointer. | |
480 int index = 2 + function()->scope()->num_parameters(); | |
481 __ mov(receiver_reg(), Operand(ebp, index * kPointerSize)); | |
482 } | |
483 | |
484 | |
485 void FastCodeGenerator::EmitGlobalVariableLoad(Handle<Object> cell) { | |
486 ASSERT(!destination().is(no_reg)); | |
487 ASSERT(cell->IsJSGlobalPropertyCell()); | |
488 | |
489 __ mov(destination(), Immediate(cell)); | |
490 __ mov(destination(), | |
491 FieldOperand(destination(), JSGlobalPropertyCell::kValueOffset)); | |
492 if (FLAG_debug_code) { | |
493 __ cmp(destination(), Factory::the_hole_value()); | |
494 __ Check(not_equal, "DontDelete cells can't contain the hole"); | |
495 } | |
496 | |
497 // The loaded value is not known to be a smi. | |
498 clear_as_smi(destination()); | |
499 } | |
500 | |
501 | |
502 void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) { | |
503 LookupResult lookup; | |
504 info()->receiver()->Lookup(*name, &lookup); | |
505 | |
506 ASSERT(lookup.holder() == *info()->receiver()); | |
507 ASSERT(lookup.type() == FIELD); | |
508 Handle<Map> map(Handle<HeapObject>::cast(info()->receiver())->map()); | |
509 int index = lookup.GetFieldIndex() - map->inobject_properties(); | |
510 int offset = index * kPointerSize; | |
511 | |
512 // We will emit the write barrier unless the stored value is statically | |
513 // known to be a smi. | |
514 bool needs_write_barrier = !is_smi(accumulator0()); | |
515 | |
516 // Perform the store. Negative offsets are inobject properties. | |
517 if (offset < 0) { | |
518 offset += map->instance_size(); | |
519 __ mov(FieldOperand(receiver_reg(), offset), accumulator0()); | |
520 if (needs_write_barrier) { | |
521 // Preserve receiver from write barrier. | |
522 __ mov(scratch0(), receiver_reg()); | |
523 } | |
524 } else { | |
525 offset += FixedArray::kHeaderSize; | |
526 __ mov(scratch0(), | |
527 FieldOperand(receiver_reg(), JSObject::kPropertiesOffset)); | |
528 __ mov(FieldOperand(scratch0(), offset), accumulator0()); | |
529 } | |
530 | |
531 if (needs_write_barrier) { | |
532 if (destination().is(no_reg)) { | |
533 // After RecordWrite accumulator0 is only accidently a smi, but it is | |
534 // already marked as not known to be one. | |
535 __ RecordWrite(scratch0(), offset, accumulator0(), scratch1()); | |
536 } else { | |
537 // Copy the value to the other accumulator to preserve a copy from the | |
538 // write barrier. One of the accumulators is available as a scratch | |
539 // register. Neither is a smi. | |
540 __ mov(accumulator1(), accumulator0()); | |
541 clear_as_smi(accumulator1()); | |
542 Register value_scratch = other_accumulator(destination()); | |
543 __ RecordWrite(scratch0(), offset, value_scratch, scratch1()); | |
544 } | |
545 } else if (destination().is(accumulator1())) { | |
546 __ mov(accumulator1(), accumulator0()); | |
547 // Is a smi because we do not need the write barrier. | |
548 set_as_smi(accumulator1()); | |
549 } | |
550 } | |
551 | |
552 | |
553 void FastCodeGenerator::EmitThisPropertyLoad(Handle<String> name) { | |
554 ASSERT(!destination().is(no_reg)); | |
555 LookupResult lookup; | |
556 info()->receiver()->Lookup(*name, &lookup); | |
557 | |
558 ASSERT(lookup.holder() == *info()->receiver()); | |
559 ASSERT(lookup.type() == FIELD); | |
560 Handle<Map> map(Handle<HeapObject>::cast(info()->receiver())->map()); | |
561 int index = lookup.GetFieldIndex() - map->inobject_properties(); | |
562 int offset = index * kPointerSize; | |
563 | |
564 // Perform the load. Negative offsets are inobject properties. | |
565 if (offset < 0) { | |
566 offset += map->instance_size(); | |
567 __ mov(destination(), FieldOperand(receiver_reg(), offset)); | |
568 } else { | |
569 offset += FixedArray::kHeaderSize; | |
570 __ mov(scratch0(), | |
571 FieldOperand(receiver_reg(), JSObject::kPropertiesOffset)); | |
572 __ mov(destination(), FieldOperand(scratch0(), offset)); | |
573 } | |
574 | |
575 // The loaded value is not known to be a smi. | |
576 clear_as_smi(destination()); | |
577 } | |
578 | |
579 | |
580 void FastCodeGenerator::EmitBitOr() { | |
581 if (is_smi(accumulator0()) && is_smi(accumulator1())) { | |
582 // If both operands are known to be a smi then there is no need to check | |
583 // the operands or result. There is no need to perform the operation in | |
584 // an effect context. | |
585 if (!destination().is(no_reg)) { | |
586 // Leave the result in the destination register. Bitwise or is | |
587 // commutative. | |
588 __ or_(destination(), Operand(other_accumulator(destination()))); | |
589 } | |
590 } else { | |
591 // Left is in accumulator1, right in accumulator0. | |
592 Label* bailout = NULL; | |
593 if (destination().is(accumulator0())) { | |
594 __ mov(scratch0(), accumulator0()); | |
595 __ or_(destination(), Operand(accumulator1())); // Or is commutative. | |
596 __ test(destination(), Immediate(kSmiTagMask)); | |
597 bailout = info()->AddBailout(accumulator1(), scratch0()); // Left, right. | |
598 } else if (destination().is(accumulator1())) { | |
599 __ mov(scratch0(), accumulator1()); | |
600 __ or_(destination(), Operand(accumulator0())); | |
601 __ test(destination(), Immediate(kSmiTagMask)); | |
602 bailout = info()->AddBailout(scratch0(), accumulator0()); | |
603 } else { | |
604 ASSERT(destination().is(no_reg)); | |
605 __ mov(scratch0(), accumulator1()); | |
606 __ or_(scratch0(), Operand(accumulator0())); | |
607 __ test(scratch0(), Immediate(kSmiTagMask)); | |
608 bailout = info()->AddBailout(accumulator1(), accumulator0()); | |
609 } | |
610 __ j(not_zero, bailout, not_taken); | |
611 } | |
612 | |
613 // If we didn't bailout, the result (in fact, both inputs too) is known to | |
614 // be a smi. | |
615 set_as_smi(accumulator0()); | |
616 set_as_smi(accumulator1()); | |
617 } | |
618 | |
619 | |
620 void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { | |
621 ASSERT(info_ == NULL); | |
622 info_ = compilation_info; | |
623 Comment cmnt(masm_, "[ function compiled by fast code generator"); | |
624 | |
625 // Save the caller's frame pointer and set up our own. | |
626 Comment prologue_cmnt(masm(), ";; Prologue"); | |
627 __ push(ebp); | |
628 __ mov(ebp, esp); | |
629 __ push(esi); // Context. | |
630 __ push(edi); // Closure. | |
631 // Note that we keep a live register reference to esi (context) at this | |
632 // point. | |
633 | |
634 Label* bailout_to_beginning = info()->AddBailout(); | |
635 // Receiver (this) is allocated to a fixed register. | |
636 if (info()->has_this_properties()) { | |
637 Comment cmnt(masm(), ";; MapCheck(this)"); | |
638 if (FLAG_print_ir) { | |
639 PrintF("#: MapCheck(this)\n"); | |
640 } | |
641 ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject()); | |
642 Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver()); | |
643 Handle<Map> map(object->map()); | |
644 EmitLoadReceiver(); | |
645 __ CheckMap(receiver_reg(), map, bailout_to_beginning, false); | |
646 } | |
647 | |
648 // If there is a global variable access check if the global object is the | |
649 // same as at lazy-compilation time. | |
650 if (info()->has_globals()) { | |
651 Comment cmnt(masm(), ";; MapCheck(GLOBAL)"); | |
652 if (FLAG_print_ir) { | |
653 PrintF("#: MapCheck(GLOBAL)\n"); | |
654 } | |
655 ASSERT(info()->has_global_object()); | |
656 Handle<Map> map(info()->global_object()->map()); | |
657 __ mov(scratch0(), CodeGenerator::GlobalObject()); | |
658 __ CheckMap(scratch0(), map, bailout_to_beginning, true); | |
659 } | |
660 | |
661 VisitStatements(function()->body()); | |
662 | |
663 Comment return_cmnt(masm(), ";; Return(<undefined>)"); | |
664 if (FLAG_print_ir) { | |
665 PrintF("#: Return(<undefined>)\n"); | |
666 } | |
667 __ mov(eax, Factory::undefined_value()); | |
668 __ mov(esp, ebp); | |
669 __ pop(ebp); | |
670 __ ret((scope()->num_parameters() + 1) * kPointerSize); | |
671 } | |
672 | |
673 | |
674 void FastCodeGenerator::VisitDeclaration(Declaration* decl) { | |
675 UNREACHABLE(); | |
676 } | |
677 | |
678 | |
679 void FastCodeGenerator::VisitBlock(Block* stmt) { | |
680 VisitStatements(stmt->statements()); | |
681 } | |
682 | |
683 | |
684 void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { | |
685 Visit(stmt->expression()); | |
686 } | |
687 | |
688 | |
689 void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { | |
690 // Nothing to do. | |
691 } | |
692 | |
693 | |
694 void FastCodeGenerator::VisitIfStatement(IfStatement* stmt) { | |
695 UNREACHABLE(); | |
696 } | |
697 | |
698 | |
699 void FastCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { | |
700 UNREACHABLE(); | |
701 } | |
702 | |
703 | |
704 void FastCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { | |
705 UNREACHABLE(); | |
706 } | |
707 | |
708 | |
709 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | |
710 UNREACHABLE(); | |
711 } | |
712 | |
713 | |
714 void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) { | |
715 UNREACHABLE(); | |
716 } | |
717 | |
718 | |
719 void FastCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) { | |
720 UNREACHABLE(); | |
721 } | |
722 | |
723 | |
724 void FastCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | |
725 UNREACHABLE(); | |
726 } | |
727 | |
728 | |
729 void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { | |
730 UNREACHABLE(); | |
731 } | |
732 | |
733 | |
734 void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { | |
735 UNREACHABLE(); | |
736 } | |
737 | |
738 | |
739 void FastCodeGenerator::VisitForStatement(ForStatement* stmt) { | |
740 UNREACHABLE(); | |
741 } | |
742 | |
743 | |
744 void FastCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | |
745 UNREACHABLE(); | |
746 } | |
747 | |
748 | |
749 void FastCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { | |
750 UNREACHABLE(); | |
751 } | |
752 | |
753 | |
754 void FastCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | |
755 UNREACHABLE(); | |
756 } | |
757 | |
758 | |
759 void FastCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { | |
760 UNREACHABLE(); | |
761 } | |
762 | |
763 | |
764 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | |
765 UNREACHABLE(); | |
766 } | |
767 | |
768 | |
769 void FastCodeGenerator::VisitSharedFunctionInfoLiteral( | |
770 SharedFunctionInfoLiteral* expr) { | |
771 UNREACHABLE(); | |
772 } | |
773 | |
774 | |
775 void FastCodeGenerator::VisitConditional(Conditional* expr) { | |
776 UNREACHABLE(); | |
777 } | |
778 | |
779 | |
780 void FastCodeGenerator::VisitSlot(Slot* expr) { | |
781 UNREACHABLE(); | |
782 } | |
783 | |
784 | |
785 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | |
786 ASSERT(expr->var()->is_global() && !expr->var()->is_this()); | |
787 // Check if we can compile a global variable load directly from the cell. | |
788 ASSERT(info()->has_global_object()); | |
789 LookupResult lookup; | |
790 info()->global_object()->Lookup(*expr->name(), &lookup); | |
791 // We only support normal (non-accessor/interceptor) DontDelete properties | |
792 // for now. | |
793 ASSERT(lookup.IsProperty()); | |
794 ASSERT_EQ(NORMAL, lookup.type()); | |
795 ASSERT(lookup.IsDontDelete()); | |
796 Handle<Object> cell(info()->global_object()->GetPropertyCell(&lookup)); | |
797 | |
798 // Global variable lookups do not have side effects, so we do not need to | |
799 // emit code if we are in an effect context. | |
800 if (!destination().is(no_reg)) { | |
801 Comment cmnt(masm(), ";; Global"); | |
802 if (FLAG_print_ir) { | |
803 SmartPointer<char> name = expr->name()->ToCString(); | |
804 PrintF("%d: t%d = Global(%s)\n", expr->num(), | |
805 expr->num(), *name); | |
806 } | |
807 EmitGlobalVariableLoad(cell); | |
808 } | |
809 } | |
810 | |
811 | |
812 void FastCodeGenerator::VisitLiteral(Literal* expr) { | |
813 UNREACHABLE(); | |
814 } | |
815 | |
816 | |
817 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | |
818 UNREACHABLE(); | |
819 } | |
820 | |
821 | |
822 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | |
823 UNREACHABLE(); | |
824 } | |
825 | |
826 | |
827 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | |
828 UNREACHABLE(); | |
829 } | |
830 | |
831 | |
832 void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) { | |
833 UNREACHABLE(); | |
834 } | |
835 | |
836 | |
837 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | |
838 // Known to be a simple this property assignment. Effectively a unary | |
839 // operation. | |
840 { Register my_destination = destination(); | |
841 set_destination(accumulator0()); | |
842 Visit(expr->value()); | |
843 set_destination(my_destination); | |
844 } | |
845 | |
846 Property* prop = expr->target()->AsProperty(); | |
847 ASSERT_NOT_NULL(prop); | |
848 ASSERT_NOT_NULL(prop->obj()->AsVariableProxy()); | |
849 ASSERT(prop->obj()->AsVariableProxy()->var()->is_this()); | |
850 ASSERT(prop->key()->IsPropertyName()); | |
851 Handle<String> name = | |
852 Handle<String>::cast(prop->key()->AsLiteral()->handle()); | |
853 | |
854 Comment cmnt(masm(), ";; Store to this"); | |
855 if (FLAG_print_ir) { | |
856 SmartPointer<char> name_string = name->ToCString(); | |
857 PrintF("%d: ", expr->num()); | |
858 if (!destination().is(no_reg)) PrintF("t%d = ", expr->num()); | |
859 PrintF("Store(this, \"%s\", t%d)\n", *name_string, | |
860 expr->value()->num()); | |
861 } | |
862 | |
863 EmitThisPropertyStore(name); | |
864 } | |
865 | |
866 | |
867 void FastCodeGenerator::VisitThrow(Throw* expr) { | |
868 UNREACHABLE(); | |
869 } | |
870 | |
871 | |
872 void FastCodeGenerator::VisitProperty(Property* expr) { | |
873 ASSERT_NOT_NULL(expr->obj()->AsVariableProxy()); | |
874 ASSERT(expr->obj()->AsVariableProxy()->var()->is_this()); | |
875 ASSERT(expr->key()->IsPropertyName()); | |
876 if (!destination().is(no_reg)) { | |
877 Handle<String> name = | |
878 Handle<String>::cast(expr->key()->AsLiteral()->handle()); | |
879 | |
880 Comment cmnt(masm(), ";; Load from this"); | |
881 if (FLAG_print_ir) { | |
882 SmartPointer<char> name_string = name->ToCString(); | |
883 PrintF("%d: t%d = Load(this, \"%s\")\n", | |
884 expr->num(), expr->num(), *name_string); | |
885 } | |
886 EmitThisPropertyLoad(name); | |
887 } | |
888 } | |
889 | |
890 | |
891 void FastCodeGenerator::VisitCall(Call* expr) { | |
892 UNREACHABLE(); | |
893 } | |
894 | |
895 | |
896 void FastCodeGenerator::VisitCallNew(CallNew* expr) { | |
897 UNREACHABLE(); | |
898 } | |
899 | |
900 | |
901 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | |
902 UNREACHABLE(); | |
903 } | |
904 | |
905 | |
906 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | |
907 UNREACHABLE(); | |
908 } | |
909 | |
910 | |
911 void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { | |
912 UNREACHABLE(); | |
913 } | |
914 | |
915 | |
916 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | |
917 // We support limited binary operations: bitwise OR only allowed to be | |
918 // nested on the left. | |
919 ASSERT(expr->op() == Token::BIT_OR); | |
920 ASSERT(expr->right()->IsLeaf()); | |
921 | |
922 { Register my_destination = destination(); | |
923 set_destination(accumulator1()); | |
924 Visit(expr->left()); | |
925 set_destination(accumulator0()); | |
926 Visit(expr->right()); | |
927 set_destination(my_destination); | |
928 } | |
929 | |
930 Comment cmnt(masm(), ";; BIT_OR"); | |
931 if (FLAG_print_ir) { | |
932 PrintF("%d: ", expr->num()); | |
933 if (!destination().is(no_reg)) PrintF("t%d = ", expr->num()); | |
934 PrintF("BIT_OR(t%d, t%d)\n", expr->left()->num(), expr->right()->num()); | |
935 } | |
936 EmitBitOr(); | |
937 } | |
938 | |
939 | |
940 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | |
941 UNREACHABLE(); | |
942 } | |
943 | |
944 | |
945 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { | |
946 UNREACHABLE(); | |
947 } | |
948 | |
949 #undef __ | |
950 | |
951 | |
952 } } // namespace v8::internal | |
953 | |
954 #endif // V8_TARGET_ARCH_IA32 | |
OLD | NEW |