Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/codegen-ia32.cc

Issue 92068: Move backend specific files to separate directories. (Closed)
Patch Set: Added CPPPATH flag and made all includes use same base path. Created 11 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codegen-ia32.h ('k') | src/constants-arm.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2006-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 "debug.h"
33 #include "parser.h"
34 #include "register-allocator-inl.h"
35 #include "runtime.h"
36 #include "scopes.h"
37
38 namespace v8 { namespace internal {
39
40 #define __ ACCESS_MASM(masm_)
41
42 // -------------------------------------------------------------------------
43 // CodeGenState implementation.
44
45 CodeGenState::CodeGenState(CodeGenerator* owner)
46 : owner_(owner),
47 typeof_state_(NOT_INSIDE_TYPEOF),
48 destination_(NULL),
49 previous_(NULL) {
50 owner_->set_state(this);
51 }
52
53
54 CodeGenState::CodeGenState(CodeGenerator* owner,
55 TypeofState typeof_state,
56 ControlDestination* destination)
57 : owner_(owner),
58 typeof_state_(typeof_state),
59 destination_(destination),
60 previous_(owner->state()) {
61 owner_->set_state(this);
62 }
63
64
65 CodeGenState::~CodeGenState() {
66 ASSERT(owner_->state() == this);
67 owner_->set_state(previous_);
68 }
69
70
71 // -------------------------------------------------------------------------
72 // CodeGenerator implementation
73
74 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
75 bool is_eval)
76 : is_eval_(is_eval),
77 script_(script),
78 deferred_(8),
79 masm_(new MacroAssembler(NULL, buffer_size)),
80 scope_(NULL),
81 frame_(NULL),
82 allocator_(NULL),
83 state_(NULL),
84 loop_nesting_(0),
85 function_return_is_shadowed_(false),
86 in_spilled_code_(false) {
87 }
88
89
90 // Calling conventions:
91 // ebp: caller's frame pointer
92 // esp: stack pointer
93 // edi: called JS function
94 // esi: callee's context
95
96 void CodeGenerator::GenCode(FunctionLiteral* fun) {
97 // Record the position for debugging purposes.
98 CodeForFunctionPosition(fun);
99
100 ZoneList<Statement*>* body = fun->body();
101
102 // Initialize state.
103 ASSERT(scope_ == NULL);
104 scope_ = fun->scope();
105 ASSERT(allocator_ == NULL);
106 RegisterAllocator register_allocator(this);
107 allocator_ = &register_allocator;
108 ASSERT(frame_ == NULL);
109 frame_ = new VirtualFrame(this);
110 set_in_spilled_code(false);
111
112 // Adjust for function-level loop nesting.
113 loop_nesting_ += fun->loop_nesting();
114
115 {
116 CodeGenState state(this);
117
118 // Entry:
119 // Stack: receiver, arguments, return address.
120 // ebp: caller's frame pointer
121 // esp: stack pointer
122 // edi: called JS function
123 // esi: callee's context
124 allocator_->Initialize();
125 frame_->Enter();
126
127 #ifdef DEBUG
128 if (strlen(FLAG_stop_at) > 0 &&
129 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
130 frame_->SpillAll();
131 __ int3();
132 }
133 #endif
134
135 // Allocate space for locals and initialize them.
136 frame_->AllocateStackSlots(scope_->num_stack_slots());
137 // Initialize the function return target after the locals are set
138 // up, because it needs the expected frame height from the frame.
139 function_return_.Initialize(this, JumpTarget::BIDIRECTIONAL);
140 function_return_is_shadowed_ = false;
141
142 // Allocate the arguments object and copy the parameters into it.
143 if (scope_->arguments() != NULL) {
144 ASSERT(scope_->arguments_shadow() != NULL);
145 Comment cmnt(masm_, "[ Allocate arguments object");
146 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
147 frame_->PushFunction();
148 frame_->PushReceiverSlotAddress();
149 frame_->Push(Smi::FromInt(scope_->num_parameters()));
150 Result answer = frame_->CallStub(&stub, 3);
151 frame_->Push(&answer);
152 }
153
154 if (scope_->num_heap_slots() > 0) {
155 Comment cmnt(masm_, "[ allocate local context");
156 // Allocate local context.
157 // Get outer context and create a new context based on it.
158 frame_->PushFunction();
159 Result context = frame_->CallRuntime(Runtime::kNewContext, 1);
160
161 // Update context local.
162 frame_->SaveContextRegister();
163
164 // Verify that the runtime call result and esi agree.
165 if (FLAG_debug_code) {
166 __ cmp(context.reg(), Operand(esi));
167 __ Assert(equal, "Runtime::NewContext should end up in esi");
168 }
169 }
170
171 // TODO(1241774): Improve this code:
172 // 1) only needed if we have a context
173 // 2) no need to recompute context ptr every single time
174 // 3) don't copy parameter operand code from SlotOperand!
175 {
176 Comment cmnt2(masm_, "[ copy context parameters into .context");
177
178 // Note that iteration order is relevant here! If we have the same
179 // parameter twice (e.g., function (x, y, x)), and that parameter
180 // needs to be copied into the context, it must be the last argument
181 // passed to the parameter that needs to be copied. This is a rare
182 // case so we don't check for it, instead we rely on the copying
183 // order: such a parameter is copied repeatedly into the same
184 // context location and thus the last value is what is seen inside
185 // the function.
186 for (int i = 0; i < scope_->num_parameters(); i++) {
187 Variable* par = scope_->parameter(i);
188 Slot* slot = par->slot();
189 if (slot != NULL && slot->type() == Slot::CONTEXT) {
190 // The use of SlotOperand below is safe in unspilled code
191 // because the slot is guaranteed to be a context slot.
192 //
193 // There are no parameters in the global scope.
194 ASSERT(!scope_->is_global_scope());
195 frame_->PushParameterAt(i);
196 Result value = frame_->Pop();
197 value.ToRegister();
198
199 // SlotOperand loads context.reg() with the context object
200 // stored to, used below in RecordWrite.
201 Result context = allocator_->Allocate();
202 ASSERT(context.is_valid());
203 __ mov(SlotOperand(slot, context.reg()), value.reg());
204 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
205 Result scratch = allocator_->Allocate();
206 ASSERT(scratch.is_valid());
207 frame_->Spill(context.reg());
208 frame_->Spill(value.reg());
209 __ RecordWrite(context.reg(), offset, value.reg(), scratch.reg());
210 }
211 }
212 }
213
214 // This section stores the pointer to the arguments object that
215 // was allocated and copied into above. If the address was not
216 // saved to TOS, we push ecx onto the stack.
217 //
218 // Store the arguments object. This must happen after context
219 // initialization because the arguments object may be stored in the
220 // context.
221 if (scope_->arguments() != NULL) {
222 Comment cmnt(masm_, "[ store arguments object");
223 { Reference shadow_ref(this, scope_->arguments_shadow());
224 ASSERT(shadow_ref.is_slot());
225 { Reference arguments_ref(this, scope_->arguments());
226 ASSERT(arguments_ref.is_slot());
227 // Here we rely on the convenient property that references to slot
228 // take up zero space in the frame (ie, it doesn't matter that the
229 // stored value is actually below the reference on the frame).
230 arguments_ref.SetValue(NOT_CONST_INIT);
231 }
232 shadow_ref.SetValue(NOT_CONST_INIT);
233 }
234 frame_->Drop(); // Value is no longer needed.
235 }
236
237 // Generate code to 'execute' declarations and initialize functions
238 // (source elements). In case of an illegal redeclaration we need to
239 // handle that instead of processing the declarations.
240 if (scope_->HasIllegalRedeclaration()) {
241 Comment cmnt(masm_, "[ illegal redeclarations");
242 scope_->VisitIllegalRedeclaration(this);
243 } else {
244 Comment cmnt(masm_, "[ declarations");
245 ProcessDeclarations(scope_->declarations());
246 // Bail out if a stack-overflow exception occurred when processing
247 // declarations.
248 if (HasStackOverflow()) return;
249 }
250
251 if (FLAG_trace) {
252 frame_->CallRuntime(Runtime::kTraceEnter, 0);
253 // Ignore the return value.
254 }
255 CheckStack();
256
257 // Compile the body of the function in a vanilla state. Don't
258 // bother compiling all the code if the scope has an illegal
259 // redeclaration.
260 if (!scope_->HasIllegalRedeclaration()) {
261 Comment cmnt(masm_, "[ function body");
262 #ifdef DEBUG
263 bool is_builtin = Bootstrapper::IsActive();
264 bool should_trace =
265 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
266 if (should_trace) {
267 frame_->CallRuntime(Runtime::kDebugTrace, 0);
268 // Ignore the return value.
269 }
270 #endif
271 VisitStatements(body);
272
273 // Handle the return from the function.
274 if (has_valid_frame()) {
275 // If there is a valid frame, control flow can fall off the end of
276 // the body. In that case there is an implicit return statement.
277 ASSERT(!function_return_is_shadowed_);
278 CodeForReturnPosition(fun);
279 frame_->PrepareForReturn();
280 Result undefined(Factory::undefined_value(), this);
281 if (function_return_.is_bound()) {
282 function_return_.Jump(&undefined);
283 } else {
284 // Though this is a (possibly) backward block, the frames
285 // can only differ on their top element.
286 function_return_.Bind(&undefined, 1);
287 GenerateReturnSequence(&undefined);
288 }
289 } else if (function_return_.is_linked()) {
290 // If the return target has dangling jumps to it, then we have not
291 // yet generated the return sequence. This can happen when (a)
292 // control does not flow off the end of the body so we did not
293 // compile an artificial return statement just above, and (b) there
294 // are return statements in the body but (c) they are all shadowed.
295 Result return_value(this);
296 // Though this is a (possibly) backward block, the frames can
297 // only differ on their top element.
298 function_return_.Bind(&return_value, 1);
299 GenerateReturnSequence(&return_value);
300 }
301 }
302 }
303
304 // Adjust for function-level loop nesting.
305 loop_nesting_ -= fun->loop_nesting();
306
307 // Code generation state must be reset.
308 ASSERT(state_ == NULL);
309 ASSERT(loop_nesting() == 0);
310 ASSERT(!function_return_is_shadowed_);
311 function_return_.Unuse();
312 DeleteFrame();
313
314 // Process any deferred code using the register allocator.
315 if (HasStackOverflow()) {
316 ClearDeferred();
317 } else {
318 ProcessDeferred();
319 }
320
321 // There is no need to delete the register allocator, it is a
322 // stack-allocated local.
323 allocator_ = NULL;
324 scope_ = NULL;
325 }
326
327
328 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
329 // Currently, this assertion will fail if we try to assign to
330 // a constant variable that is constant because it is read-only
331 // (such as the variable referring to a named function expression).
332 // We need to implement assignments to read-only variables.
333 // Ideally, we should do this during AST generation (by converting
334 // such assignments into expression statements); however, in general
335 // we may not be able to make the decision until past AST generation,
336 // that is when the entire program is known.
337 ASSERT(slot != NULL);
338 int index = slot->index();
339 switch (slot->type()) {
340 case Slot::PARAMETER:
341 return frame_->ParameterAt(index);
342
343 case Slot::LOCAL:
344 return frame_->LocalAt(index);
345
346 case Slot::CONTEXT: {
347 // Follow the context chain if necessary.
348 ASSERT(!tmp.is(esi)); // do not overwrite context register
349 Register context = esi;
350 int chain_length = scope()->ContextChainLength(slot->var()->scope());
351 for (int i = 0; i < chain_length; i++) {
352 // Load the closure.
353 // (All contexts, even 'with' contexts, have a closure,
354 // and it is the same for all contexts inside a function.
355 // There is no need to go to the function context first.)
356 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
357 // Load the function context (which is the incoming, outer context).
358 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
359 context = tmp;
360 }
361 // We may have a 'with' context now. Get the function context.
362 // (In fact this mov may never be the needed, since the scope analysis
363 // may not permit a direct context access in this case and thus we are
364 // always at a function context. However it is safe to dereference be-
365 // cause the function context of a function context is itself. Before
366 // deleting this mov we should try to create a counter-example first,
367 // though...)
368 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
369 return ContextOperand(tmp, index);
370 }
371
372 default:
373 UNREACHABLE();
374 return Operand(eax);
375 }
376 }
377
378
379 Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot,
380 Result tmp,
381 JumpTarget* slow) {
382 ASSERT(slot->type() == Slot::CONTEXT);
383 ASSERT(tmp.is_register());
384 Result context(esi, this);
385
386 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
387 if (s->num_heap_slots() > 0) {
388 if (s->calls_eval()) {
389 // Check that extension is NULL.
390 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX),
391 Immediate(0));
392 slow->Branch(not_equal, not_taken);
393 }
394 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::CLOSURE_INDEX));
395 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset));
396 context = tmp;
397 }
398 }
399 // Check that last extension is NULL.
400 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX),
401 Immediate(0));
402 slow->Branch(not_equal, not_taken);
403 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::FCONTEXT_INDEX));
404 return ContextOperand(tmp.reg(), slot->index());
405 }
406
407
408 // Emit code to load the value of an expression to the top of the
409 // frame. If the expression is boolean-valued it may be compiled (or
410 // partially compiled) into control flow to the control destination.
411 // If force_control is true, control flow is forced.
412 void CodeGenerator::LoadCondition(Expression* x,
413 TypeofState typeof_state,
414 ControlDestination* dest,
415 bool force_control) {
416 ASSERT(!in_spilled_code());
417 int original_height = frame_->height();
418
419 { CodeGenState new_state(this, typeof_state, dest);
420 Visit(x);
421
422 // If we hit a stack overflow, we may not have actually visited
423 // the expression. In that case, we ensure that we have a
424 // valid-looking frame state because we will continue to generate
425 // code as we unwind the C++ stack.
426 //
427 // It's possible to have both a stack overflow and a valid frame
428 // state (eg, a subexpression overflowed, visiting it returned
429 // with a dummied frame state, and visiting this expression
430 // returned with a normal-looking state).
431 if (HasStackOverflow() &&
432 !dest->is_used() &&
433 frame_->height() == original_height) {
434 dest->Goto(true);
435 }
436 }
437
438 if (force_control && !dest->is_used()) {
439 // Convert the TOS value into flow to the control destination.
440 ToBoolean(dest);
441 }
442
443 ASSERT(!(force_control && !dest->is_used()));
444 ASSERT(dest->is_used() || frame_->height() == original_height + 1);
445 }
446
447
448 void CodeGenerator::LoadAndSpill(Expression* expression,
449 TypeofState typeof_state) {
450 ASSERT(in_spilled_code());
451 set_in_spilled_code(false);
452 Load(expression, typeof_state);
453 frame_->SpillAll();
454 set_in_spilled_code(true);
455 }
456
457
458 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
459 #ifdef DEBUG
460 int original_height = frame_->height();
461 #endif
462 ASSERT(!in_spilled_code());
463 JumpTarget true_target(this);
464 JumpTarget false_target(this);
465 ControlDestination dest(&true_target, &false_target, true);
466 LoadCondition(x, typeof_state, &dest, false);
467
468 if (dest.false_was_fall_through()) {
469 // The false target was just bound.
470 JumpTarget loaded(this);
471 frame_->Push(Factory::false_value());
472 // There may be dangling jumps to the true target.
473 if (true_target.is_linked()) {
474 loaded.Jump();
475 true_target.Bind();
476 frame_->Push(Factory::true_value());
477 loaded.Bind();
478 }
479
480 } else if (dest.is_used()) {
481 // There is true, and possibly false, control flow (with true as
482 // the fall through).
483 JumpTarget loaded(this);
484 frame_->Push(Factory::true_value());
485 if (false_target.is_linked()) {
486 loaded.Jump();
487 false_target.Bind();
488 frame_->Push(Factory::false_value());
489 loaded.Bind();
490 }
491
492 } else {
493 // We have a valid value on top of the frame, but we still may
494 // have dangling jumps to the true and false targets from nested
495 // subexpressions (eg, the left subexpressions of the
496 // short-circuited boolean operators).
497 ASSERT(has_valid_frame());
498 if (true_target.is_linked() || false_target.is_linked()) {
499 JumpTarget loaded(this);
500 loaded.Jump(); // Don't lose the current TOS.
501 if (true_target.is_linked()) {
502 true_target.Bind();
503 frame_->Push(Factory::true_value());
504 if (false_target.is_linked()) {
505 loaded.Jump();
506 }
507 }
508 if (false_target.is_linked()) {
509 false_target.Bind();
510 frame_->Push(Factory::false_value());
511 }
512 loaded.Bind();
513 }
514 }
515
516 ASSERT(has_valid_frame());
517 ASSERT(frame_->height() == original_height + 1);
518 }
519
520
521 void CodeGenerator::LoadGlobal() {
522 if (in_spilled_code()) {
523 frame_->EmitPush(GlobalObject());
524 } else {
525 Result temp = allocator_->Allocate();
526 __ mov(temp.reg(), GlobalObject());
527 frame_->Push(&temp);
528 }
529 }
530
531
532 void CodeGenerator::LoadGlobalReceiver() {
533 Result temp = allocator_->Allocate();
534 Register reg = temp.reg();
535 __ mov(reg, GlobalObject());
536 __ mov(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset));
537 frame_->Push(&temp);
538 }
539
540
541 // TODO(1241834): Get rid of this function in favor of just using Load, now
542 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global
543 // variables w/o reference errors elsewhere.
544 void CodeGenerator::LoadTypeofExpression(Expression* x) {
545 Variable* variable = x->AsVariableProxy()->AsVariable();
546 if (variable != NULL && !variable->is_this() && variable->is_global()) {
547 // NOTE: This is somewhat nasty. We force the compiler to load
548 // the variable as if through '<global>.<variable>' to make sure we
549 // do not get reference errors.
550 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX);
551 Literal key(variable->name());
552 // TODO(1241834): Fetch the position from the variable instead of using
553 // no position.
554 Property property(&global, &key, RelocInfo::kNoPosition);
555 Load(&property);
556 } else {
557 Load(x, INSIDE_TYPEOF);
558 }
559 }
560
561
562 Reference::Reference(CodeGenerator* cgen, Expression* expression)
563 : cgen_(cgen), expression_(expression), type_(ILLEGAL) {
564 cgen->LoadReference(this);
565 }
566
567
568 Reference::~Reference() {
569 cgen_->UnloadReference(this);
570 }
571
572
573 void CodeGenerator::LoadReference(Reference* ref) {
574 // References are loaded from both spilled and unspilled code. Set the
575 // state to unspilled to allow that (and explicitly spill after
576 // construction at the construction sites).
577 bool was_in_spilled_code = in_spilled_code_;
578 in_spilled_code_ = false;
579
580 Comment cmnt(masm_, "[ LoadReference");
581 Expression* e = ref->expression();
582 Property* property = e->AsProperty();
583 Variable* var = e->AsVariableProxy()->AsVariable();
584
585 if (property != NULL) {
586 // The expression is either a property or a variable proxy that rewrites
587 // to a property.
588 Load(property->obj());
589 // We use a named reference if the key is a literal symbol, unless it is
590 // a string that can be legally parsed as an integer. This is because
591 // otherwise we will not get into the slow case code that handles [] on
592 // String objects.
593 Literal* literal = property->key()->AsLiteral();
594 uint32_t dummy;
595 if (literal != NULL &&
596 literal->handle()->IsSymbol() &&
597 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
598 ref->set_type(Reference::NAMED);
599 } else {
600 Load(property->key());
601 ref->set_type(Reference::KEYED);
602 }
603 } else if (var != NULL) {
604 // The expression is a variable proxy that does not rewrite to a
605 // property. Global variables are treated as named property references.
606 if (var->is_global()) {
607 LoadGlobal();
608 ref->set_type(Reference::NAMED);
609 } else {
610 ASSERT(var->slot() != NULL);
611 ref->set_type(Reference::SLOT);
612 }
613 } else {
614 // Anything else is a runtime error.
615 Load(e);
616 frame_->CallRuntime(Runtime::kThrowReferenceError, 1);
617 }
618
619 in_spilled_code_ = was_in_spilled_code;
620 }
621
622
623 void CodeGenerator::UnloadReference(Reference* ref) {
624 // Pop a reference from the stack while preserving TOS.
625 Comment cmnt(masm_, "[ UnloadReference");
626 frame_->Nip(ref->size());
627 }
628
629
630 class ToBooleanStub: public CodeStub {
631 public:
632 ToBooleanStub() { }
633
634 void Generate(MacroAssembler* masm);
635
636 private:
637 Major MajorKey() { return ToBoolean; }
638 int MinorKey() { return 0; }
639 };
640
641
642 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and
643 // convert it to a boolean in the condition code register or jump to
644 // 'false_target'/'true_target' as appropriate.
645 void CodeGenerator::ToBoolean(ControlDestination* dest) {
646 Comment cmnt(masm_, "[ ToBoolean");
647
648 // The value to convert should be popped from the frame.
649 Result value = frame_->Pop();
650 value.ToRegister();
651 // Fast case checks.
652
653 // 'false' => false.
654 __ cmp(value.reg(), Factory::false_value());
655 dest->false_target()->Branch(equal);
656
657 // 'true' => true.
658 __ cmp(value.reg(), Factory::true_value());
659 dest->true_target()->Branch(equal);
660
661 // 'undefined' => false.
662 __ cmp(value.reg(), Factory::undefined_value());
663 dest->false_target()->Branch(equal);
664
665 // Smi => false iff zero.
666 ASSERT(kSmiTag == 0);
667 __ test(value.reg(), Operand(value.reg()));
668 dest->false_target()->Branch(zero);
669 __ test(value.reg(), Immediate(kSmiTagMask));
670 dest->true_target()->Branch(zero);
671
672 // Call the stub for all other cases.
673 frame_->Push(&value); // Undo the Pop() from above.
674 ToBooleanStub stub;
675 Result temp = frame_->CallStub(&stub, 1);
676 // Convert the result to a condition code.
677 __ test(temp.reg(), Operand(temp.reg()));
678 temp.Unuse();
679 dest->Split(not_equal);
680 }
681
682
683 class FloatingPointHelper : public AllStatic {
684 public:
685 // Code pattern for loading floating point values. Input values must
686 // be either smi or heap number objects (fp values). Requirements:
687 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as
688 // floating point numbers on FPU stack.
689 static void LoadFloatOperands(MacroAssembler* masm, Register scratch);
690 // Test if operands are smi or number objects (fp). Requirements:
691 // operand_1 in eax, operand_2 in edx; falls through on float
692 // operands, jumps to the non_float label otherwise.
693 static void CheckFloatOperands(MacroAssembler* masm,
694 Label* non_float,
695 Register scratch);
696 // Allocate a heap number in new space with undefined value.
697 // Returns tagged pointer in eax, or jumps to need_gc if new space is full.
698 static void AllocateHeapNumber(MacroAssembler* masm,
699 Label* need_gc,
700 Register scratch1,
701 Register scratch2);
702 };
703
704
705 // Flag that indicates whether or not the code that handles smi arguments
706 // should be placed in the stub, inlined, or omitted entirely.
707 enum GenericBinaryFlags {
708 SMI_CODE_IN_STUB,
709 SMI_CODE_INLINED
710 };
711
712
713 class GenericBinaryOpStub: public CodeStub {
714 public:
715 GenericBinaryOpStub(Token::Value op,
716 OverwriteMode mode,
717 GenericBinaryFlags flags)
718 : op_(op), mode_(mode), flags_(flags) {
719 ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
720 }
721
722 void GenerateSmiCode(MacroAssembler* masm, Label* slow);
723
724 private:
725 Token::Value op_;
726 OverwriteMode mode_;
727 GenericBinaryFlags flags_;
728
729 const char* GetName();
730
731 #ifdef DEBUG
732 void Print() {
733 PrintF("GenericBinaryOpStub (op %s), (mode %d, flags %d)\n",
734 Token::String(op_),
735 static_cast<int>(mode_),
736 static_cast<int>(flags_));
737 }
738 #endif
739
740 // Minor key encoding in 16 bits FOOOOOOOOOOOOOMM.
741 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
742 class OpBits: public BitField<Token::Value, 2, 13> {};
743 class FlagBits: public BitField<GenericBinaryFlags, 15, 1> {};
744
745 Major MajorKey() { return GenericBinaryOp; }
746 int MinorKey() {
747 // Encode the parameters in a unique 16 bit value.
748 return OpBits::encode(op_)
749 | ModeBits::encode(mode_)
750 | FlagBits::encode(flags_);
751 }
752 void Generate(MacroAssembler* masm);
753 };
754
755
756 const char* GenericBinaryOpStub::GetName() {
757 switch (op_) {
758 case Token::ADD: return "GenericBinaryOpStub_ADD";
759 case Token::SUB: return "GenericBinaryOpStub_SUB";
760 case Token::MUL: return "GenericBinaryOpStub_MUL";
761 case Token::DIV: return "GenericBinaryOpStub_DIV";
762 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
763 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
764 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
765 case Token::SAR: return "GenericBinaryOpStub_SAR";
766 case Token::SHL: return "GenericBinaryOpStub_SHL";
767 case Token::SHR: return "GenericBinaryOpStub_SHR";
768 default: return "GenericBinaryOpStub";
769 }
770 }
771
772
773 // A deferred code class implementing binary operations on likely smis.
774 // This class generates both inline code and deferred code.
775 // The fastest path is implemented inline. Deferred code calls
776 // the GenericBinaryOpStub stub for slow cases.
777 class DeferredInlineBinaryOperation: public DeferredCode {
778 public:
779 DeferredInlineBinaryOperation(CodeGenerator* generator,
780 Token::Value op,
781 OverwriteMode mode,
782 GenericBinaryFlags flags)
783 : DeferredCode(generator), stub_(op, mode, flags), op_(op) {
784 set_comment("[ DeferredInlineBinaryOperation");
785 }
786
787 // Consumes its arguments, left and right, leaving them invalid.
788 Result GenerateInlineCode(Result* left, Result* right);
789
790 virtual void Generate();
791
792 private:
793 GenericBinaryOpStub stub_;
794 Token::Value op_;
795 };
796
797
798 void DeferredInlineBinaryOperation::Generate() {
799 Result left(generator());
800 Result right(generator());
801 enter()->Bind(&left, &right);
802 generator()->frame()->Push(&left);
803 generator()->frame()->Push(&right);
804 Result answer = generator()->frame()->CallStub(&stub_, 2);
805 exit_.Jump(&answer);
806 }
807
808
809 void CodeGenerator::GenericBinaryOperation(Token::Value op,
810 SmiAnalysis* type,
811 OverwriteMode overwrite_mode) {
812 Comment cmnt(masm_, "[ BinaryOperation");
813 Comment cmnt_token(masm_, Token::String(op));
814
815 if (op == Token::COMMA) {
816 // Simply discard left value.
817 frame_->Nip(1);
818 return;
819 }
820
821 // Set the flags based on the operation, type and loop nesting level.
822 GenericBinaryFlags flags;
823 switch (op) {
824 case Token::BIT_OR:
825 case Token::BIT_AND:
826 case Token::BIT_XOR:
827 case Token::SHL:
828 case Token::SHR:
829 case Token::SAR:
830 // Bit operations always assume they likely operate on Smis. Still only
831 // generate the inline Smi check code if this operation is part of a loop.
832 flags = (loop_nesting() > 0)
833 ? SMI_CODE_INLINED
834 : SMI_CODE_IN_STUB;
835 break;
836
837 default:
838 // By default only inline the Smi check code for likely smis if this
839 // operation is part of a loop.
840 flags = ((loop_nesting() > 0) && type->IsLikelySmi())
841 ? SMI_CODE_INLINED
842 : SMI_CODE_IN_STUB;
843 break;
844 }
845
846 Result right = frame_->Pop();
847 Result left = frame_->Pop();
848
849 if (op == Token::ADD) {
850 bool left_is_string = left.static_type().is_jsstring();
851 bool right_is_string = right.static_type().is_jsstring();
852 if (left_is_string || right_is_string) {
853 frame_->Push(&left);
854 frame_->Push(&right);
855 Result answer(this);
856 if (left_is_string) {
857 if (right_is_string) {
858 // TODO(lrn): if (left.is_constant() && right.is_constant())
859 // -- do a compile time cons, if allocation during codegen is allowed.
860 answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
861 } else {
862 answer =
863 frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2);
864 }
865 } else if (right_is_string) {
866 answer =
867 frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2);
868 }
869 answer.set_static_type(StaticType::jsstring());
870 frame_->Push(&answer);
871 return;
872 }
873 // Neither operand is known to be a string.
874 }
875
876 bool left_is_smi = left.is_constant() && left.handle()->IsSmi();
877 bool left_is_non_smi = left.is_constant() && !left.handle()->IsSmi();
878 bool right_is_smi = right.is_constant() && right.handle()->IsSmi();
879 bool right_is_non_smi = right.is_constant() && !right.handle()->IsSmi();
880 bool generate_no_smi_code = false; // No smi code at all, inline or in stub.
881
882 if (left_is_smi && right_is_smi) {
883 // Compute the constant result at compile time, and leave it on the frame.
884 int left_int = Smi::cast(*left.handle())->value();
885 int right_int = Smi::cast(*right.handle())->value();
886 if (FoldConstantSmis(op, left_int, right_int)) return;
887 }
888
889 if (left_is_non_smi || right_is_non_smi) {
890 // Set flag so that we go straight to the slow case, with no smi code.
891 generate_no_smi_code = true;
892 } else if (right_is_smi) {
893 ConstantSmiBinaryOperation(op, &left, right.handle(),
894 type, false, overwrite_mode);
895 return;
896 } else if (left_is_smi) {
897 ConstantSmiBinaryOperation(op, &right, left.handle(),
898 type, true, overwrite_mode);
899 return;
900 }
901
902 if (flags == SMI_CODE_INLINED && !generate_no_smi_code) {
903 LikelySmiBinaryOperation(op, &left, &right, overwrite_mode);
904 } else {
905 frame_->Push(&left);
906 frame_->Push(&right);
907 // If we know the arguments aren't smis, use the binary operation stub
908 // that does not check for the fast smi case.
909 // The same stub is used for NO_SMI_CODE and SMI_CODE_INLINED.
910 if (generate_no_smi_code) {
911 flags = SMI_CODE_INLINED;
912 }
913 GenericBinaryOpStub stub(op, overwrite_mode, flags);
914 Result answer = frame_->CallStub(&stub, 2);
915 frame_->Push(&answer);
916 }
917 }
918
919
920 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) {
921 Object* answer_object = Heap::undefined_value();
922 switch (op) {
923 case Token::ADD:
924 if (Smi::IsValid(left + right)) {
925 answer_object = Smi::FromInt(left + right);
926 }
927 break;
928 case Token::SUB:
929 if (Smi::IsValid(left - right)) {
930 answer_object = Smi::FromInt(left - right);
931 }
932 break;
933 case Token::MUL: {
934 double answer = static_cast<double>(left) * right;
935 if (answer >= Smi::kMinValue && answer <= Smi::kMaxValue) {
936 // If the product is zero and the non-zero factor is negative,
937 // the spec requires us to return floating point negative zero.
938 if (answer != 0 || (left >= 0 && right >= 0)) {
939 answer_object = Smi::FromInt(static_cast<int>(answer));
940 }
941 }
942 }
943 break;
944 case Token::DIV:
945 case Token::MOD:
946 break;
947 case Token::BIT_OR:
948 answer_object = Smi::FromInt(left | right);
949 break;
950 case Token::BIT_AND:
951 answer_object = Smi::FromInt(left & right);
952 break;
953 case Token::BIT_XOR:
954 answer_object = Smi::FromInt(left ^ right);
955 break;
956
957 case Token::SHL: {
958 int shift_amount = right & 0x1F;
959 if (Smi::IsValid(left << shift_amount)) {
960 answer_object = Smi::FromInt(left << shift_amount);
961 }
962 break;
963 }
964 case Token::SHR: {
965 int shift_amount = right & 0x1F;
966 unsigned int unsigned_left = left;
967 unsigned_left >>= shift_amount;
968 if (unsigned_left <= static_cast<unsigned int>(Smi::kMaxValue)) {
969 answer_object = Smi::FromInt(unsigned_left);
970 }
971 break;
972 }
973 case Token::SAR: {
974 int shift_amount = right & 0x1F;
975 unsigned int unsigned_left = left;
976 if (left < 0) {
977 // Perform arithmetic shift of a negative number by
978 // complementing number, logical shifting, complementing again.
979 unsigned_left = ~unsigned_left;
980 unsigned_left >>= shift_amount;
981 unsigned_left = ~unsigned_left;
982 } else {
983 unsigned_left >>= shift_amount;
984 }
985 ASSERT(Smi::IsValid(unsigned_left)); // Converted to signed.
986 answer_object = Smi::FromInt(unsigned_left); // Converted to signed.
987 break;
988 }
989 default:
990 UNREACHABLE();
991 break;
992 }
993 if (answer_object == Heap::undefined_value()) {
994 return false;
995 }
996 frame_->Push(Handle<Object>(answer_object));
997 return true;
998 }
999
1000
1001 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
1002 Result* left,
1003 Result* right,
1004 OverwriteMode overwrite_mode) {
1005 // Implements a binary operation using a deferred code object
1006 // and some inline code to operate on smis quickly.
1007 DeferredInlineBinaryOperation* deferred =
1008 new DeferredInlineBinaryOperation(this, op, overwrite_mode,
1009 SMI_CODE_INLINED);
1010 // Generate the inline code that handles some smi operations,
1011 // and jumps to the deferred code for everything else.
1012 Result answer = deferred->GenerateInlineCode(left, right);
1013 deferred->BindExit(&answer);
1014 frame_->Push(&answer);
1015 }
1016
1017
1018 class DeferredInlineSmiOperation: public DeferredCode {
1019 public:
1020 DeferredInlineSmiOperation(CodeGenerator* generator,
1021 Token::Value op,
1022 Smi* value,
1023 OverwriteMode overwrite_mode)
1024 : DeferredCode(generator),
1025 op_(op),
1026 value_(value),
1027 overwrite_mode_(overwrite_mode) {
1028 set_comment("[ DeferredInlineSmiOperation");
1029 }
1030
1031 virtual void Generate();
1032
1033 private:
1034 Token::Value op_;
1035 Smi* value_;
1036 OverwriteMode overwrite_mode_;
1037 };
1038
1039
1040 void DeferredInlineSmiOperation::Generate() {
1041 Result left(generator());
1042 enter()->Bind(&left);
1043 generator()->frame()->Push(&left);
1044 generator()->frame()->Push(value_);
1045 GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED);
1046 Result answer = generator()->frame()->CallStub(&igostub, 2);
1047 exit_.Jump(&answer);
1048 }
1049
1050
1051 class DeferredInlineSmiOperationReversed: public DeferredCode {
1052 public:
1053 DeferredInlineSmiOperationReversed(CodeGenerator* generator,
1054 Token::Value op,
1055 Smi* value,
1056 OverwriteMode overwrite_mode)
1057 : DeferredCode(generator),
1058 op_(op),
1059 value_(value),
1060 overwrite_mode_(overwrite_mode) {
1061 set_comment("[ DeferredInlineSmiOperationReversed");
1062 }
1063
1064 virtual void Generate();
1065
1066 private:
1067 Token::Value op_;
1068 Smi* value_;
1069 OverwriteMode overwrite_mode_;
1070 };
1071
1072
1073 void DeferredInlineSmiOperationReversed::Generate() {
1074 Result right(generator());
1075 enter()->Bind(&right);
1076 generator()->frame()->Push(value_);
1077 generator()->frame()->Push(&right);
1078 GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED);
1079 Result answer = generator()->frame()->CallStub(&igostub, 2);
1080 exit_.Jump(&answer);
1081 }
1082
1083
1084 class DeferredInlineSmiAdd: public DeferredCode {
1085 public:
1086 DeferredInlineSmiAdd(CodeGenerator* generator,
1087 Smi* value,
1088 OverwriteMode overwrite_mode)
1089 : DeferredCode(generator),
1090 value_(value),
1091 overwrite_mode_(overwrite_mode) {
1092 set_comment("[ DeferredInlineSmiAdd");
1093 }
1094
1095 virtual void Generate();
1096
1097 private:
1098 Smi* value_;
1099 OverwriteMode overwrite_mode_;
1100 };
1101
1102
1103 void DeferredInlineSmiAdd::Generate() {
1104 // Undo the optimistic add operation and call the shared stub.
1105 Result left(generator()); // Initially left + value_.
1106 enter()->Bind(&left);
1107 left.ToRegister();
1108 generator()->frame()->Spill(left.reg());
1109 __ sub(Operand(left.reg()), Immediate(value_));
1110 generator()->frame()->Push(&left);
1111 generator()->frame()->Push(value_);
1112 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED);
1113 Result answer = generator()->frame()->CallStub(&igostub, 2);
1114 exit_.Jump(&answer);
1115 }
1116
1117
1118 class DeferredInlineSmiAddReversed: public DeferredCode {
1119 public:
1120 DeferredInlineSmiAddReversed(CodeGenerator* generator,
1121 Smi* value,
1122 OverwriteMode overwrite_mode)
1123 : DeferredCode(generator),
1124 value_(value),
1125 overwrite_mode_(overwrite_mode) {
1126 set_comment("[ DeferredInlineSmiAddReversed");
1127 }
1128
1129 virtual void Generate();
1130
1131 private:
1132 Smi* value_;
1133 OverwriteMode overwrite_mode_;
1134 };
1135
1136
1137 void DeferredInlineSmiAddReversed::Generate() {
1138 // Undo the optimistic add operation and call the shared stub.
1139 Result right(generator()); // Initially value_ + right.
1140 enter()->Bind(&right);
1141 right.ToRegister();
1142 generator()->frame()->Spill(right.reg());
1143 __ sub(Operand(right.reg()), Immediate(value_));
1144 generator()->frame()->Push(value_);
1145 generator()->frame()->Push(&right);
1146 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED);
1147 Result answer = generator()->frame()->CallStub(&igostub, 2);
1148 exit_.Jump(&answer);
1149 }
1150
1151
1152 class DeferredInlineSmiSub: public DeferredCode {
1153 public:
1154 DeferredInlineSmiSub(CodeGenerator* generator,
1155 Smi* value,
1156 OverwriteMode overwrite_mode)
1157 : DeferredCode(generator),
1158 value_(value),
1159 overwrite_mode_(overwrite_mode) {
1160 set_comment("[ DeferredInlineSmiSub");
1161 }
1162
1163 virtual void Generate();
1164
1165 private:
1166 Smi* value_;
1167 OverwriteMode overwrite_mode_;
1168 };
1169
1170
1171 void DeferredInlineSmiSub::Generate() {
1172 // Undo the optimistic sub operation and call the shared stub.
1173 Result left(generator()); // Initially left - value_.
1174 enter()->Bind(&left);
1175 left.ToRegister();
1176 generator()->frame()->Spill(left.reg());
1177 __ add(Operand(left.reg()), Immediate(value_));
1178 generator()->frame()->Push(&left);
1179 generator()->frame()->Push(value_);
1180 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED);
1181 Result answer = generator()->frame()->CallStub(&igostub, 2);
1182 exit_.Jump(&answer);
1183 }
1184
1185
1186 class DeferredInlineSmiSubReversed: public DeferredCode {
1187 public:
1188 DeferredInlineSmiSubReversed(CodeGenerator* generator,
1189 Smi* value,
1190 OverwriteMode overwrite_mode)
1191 : DeferredCode(generator),
1192 value_(value),
1193 overwrite_mode_(overwrite_mode) {
1194 set_comment("[ DeferredInlineSmiSubReversed");
1195 }
1196
1197 virtual void Generate();
1198
1199 private:
1200 Smi* value_;
1201 OverwriteMode overwrite_mode_;
1202 };
1203
1204
1205 void DeferredInlineSmiSubReversed::Generate() {
1206 // Call the shared stub.
1207 Result right(generator());
1208 enter()->Bind(&right);
1209 generator()->frame()->Push(value_);
1210 generator()->frame()->Push(&right);
1211 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED);
1212 Result answer = generator()->frame()->CallStub(&igostub, 2);
1213 exit_.Jump(&answer);
1214 }
1215
1216
1217 void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
1218 Result* operand,
1219 Handle<Object> value,
1220 SmiAnalysis* type,
1221 bool reversed,
1222 OverwriteMode overwrite_mode) {
1223 // NOTE: This is an attempt to inline (a bit) more of the code for
1224 // some possible smi operations (like + and -) when (at least) one
1225 // of the operands is a constant smi.
1226 // Consumes the argument "operand".
1227
1228 // TODO(199): Optimize some special cases of operations involving a
1229 // smi literal (multiply by 2, shift by 0, etc.).
1230 if (IsUnsafeSmi(value)) {
1231 Result unsafe_operand(value, this);
1232 if (reversed) {
1233 LikelySmiBinaryOperation(op, &unsafe_operand, operand,
1234 overwrite_mode);
1235 } else {
1236 LikelySmiBinaryOperation(op, operand, &unsafe_operand,
1237 overwrite_mode);
1238 }
1239 ASSERT(!operand->is_valid());
1240 return;
1241 }
1242
1243 // Get the literal value.
1244 Smi* smi_value = Smi::cast(*value);
1245 int int_value = smi_value->value();
1246
1247 switch (op) {
1248 case Token::ADD: {
1249 DeferredCode* deferred = NULL;
1250 if (reversed) {
1251 deferred = new DeferredInlineSmiAddReversed(this, smi_value,
1252 overwrite_mode);
1253 } else {
1254 deferred = new DeferredInlineSmiAdd(this, smi_value, overwrite_mode);
1255 }
1256 operand->ToRegister();
1257 frame_->Spill(operand->reg());
1258 __ add(Operand(operand->reg()), Immediate(value));
1259 deferred->enter()->Branch(overflow, operand, not_taken);
1260 __ test(operand->reg(), Immediate(kSmiTagMask));
1261 deferred->enter()->Branch(not_zero, operand, not_taken);
1262 deferred->BindExit(operand);
1263 frame_->Push(operand);
1264 break;
1265 }
1266
1267 case Token::SUB: {
1268 DeferredCode* deferred = NULL;
1269 Result answer(this); // Only allocate a new register if reversed.
1270 if (reversed) {
1271 answer = allocator()->Allocate();
1272 ASSERT(answer.is_valid());
1273 deferred = new DeferredInlineSmiSubReversed(this,
1274 smi_value,
1275 overwrite_mode);
1276 __ Set(answer.reg(), Immediate(value));
1277 // We are in the reversed case so they can't both be Smi constants.
1278 ASSERT(operand->is_register());
1279 __ sub(answer.reg(), Operand(operand->reg()));
1280 } else {
1281 operand->ToRegister();
1282 frame_->Spill(operand->reg());
1283 deferred = new DeferredInlineSmiSub(this,
1284 smi_value,
1285 overwrite_mode);
1286 __ sub(Operand(operand->reg()), Immediate(value));
1287 answer = *operand;
1288 }
1289 deferred->enter()->Branch(overflow, operand, not_taken);
1290 __ test(answer.reg(), Immediate(kSmiTagMask));
1291 deferred->enter()->Branch(not_zero, operand, not_taken);
1292 operand->Unuse();
1293 deferred->BindExit(&answer);
1294 frame_->Push(&answer);
1295 break;
1296 }
1297
1298 case Token::SAR: {
1299 if (reversed) {
1300 Result constant_operand(value, this);
1301 LikelySmiBinaryOperation(op, &constant_operand, operand,
1302 overwrite_mode);
1303 } else {
1304 // Only the least significant 5 bits of the shift value are used.
1305 // In the slow case, this masking is done inside the runtime call.
1306 int shift_value = int_value & 0x1f;
1307 DeferredCode* deferred =
1308 new DeferredInlineSmiOperation(this, Token::SAR, smi_value,
1309 overwrite_mode);
1310 operand->ToRegister();
1311 __ test(operand->reg(), Immediate(kSmiTagMask));
1312 deferred->enter()->Branch(not_zero, operand, not_taken);
1313 if (shift_value > 0) {
1314 frame_->Spill(operand->reg());
1315 __ sar(operand->reg(), shift_value);
1316 __ and_(operand->reg(), ~kSmiTagMask);
1317 }
1318 deferred->BindExit(operand);
1319 frame_->Push(operand);
1320 }
1321 break;
1322 }
1323
1324 case Token::SHR: {
1325 if (reversed) {
1326 Result constant_operand(value, this);
1327 LikelySmiBinaryOperation(op, &constant_operand, operand,
1328 overwrite_mode);
1329 } else {
1330 // Only the least significant 5 bits of the shift value are used.
1331 // In the slow case, this masking is done inside the runtime call.
1332 int shift_value = int_value & 0x1f;
1333 DeferredCode* deferred =
1334 new DeferredInlineSmiOperation(this, Token::SHR, smi_value,
1335 overwrite_mode);
1336 operand->ToRegister();
1337 __ test(operand->reg(), Immediate(kSmiTagMask));
1338 deferred->enter()->Branch(not_zero, operand, not_taken);
1339 Result answer = allocator()->Allocate();
1340 ASSERT(answer.is_valid());
1341 __ mov(answer.reg(), operand->reg());
1342 __ sar(answer.reg(), kSmiTagSize);
1343 __ shr(answer.reg(), shift_value);
1344 // A negative Smi shifted right two is in the positive Smi range.
1345 if (shift_value < 2) {
1346 __ test(answer.reg(), Immediate(0xc0000000));
1347 deferred->enter()->Branch(not_zero, operand, not_taken);
1348 }
1349 operand->Unuse();
1350 ASSERT(kSmiTagSize == times_2); // Adjust the code if not true.
1351 __ lea(answer.reg(),
1352 Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
1353 deferred->BindExit(&answer);
1354 frame_->Push(&answer);
1355 }
1356 break;
1357 }
1358
1359 case Token::SHL: {
1360 if (reversed) {
1361 Result constant_operand(value, this);
1362 LikelySmiBinaryOperation(op, &constant_operand, operand,
1363 overwrite_mode);
1364 } else {
1365 // Only the least significant 5 bits of the shift value are used.
1366 // In the slow case, this masking is done inside the runtime call.
1367 int shift_value = int_value & 0x1f;
1368 DeferredCode* deferred =
1369 new DeferredInlineSmiOperation(this, Token::SHL, smi_value,
1370 overwrite_mode);
1371 operand->ToRegister();
1372 __ test(operand->reg(), Immediate(kSmiTagMask));
1373 deferred->enter()->Branch(not_zero, operand, not_taken);
1374 if (shift_value != 0) {
1375 Result answer = allocator()->Allocate();
1376 ASSERT(answer.is_valid());
1377 __ mov(answer.reg(), operand->reg());
1378 ASSERT(kSmiTag == 0); // adjust code if not the case
1379 // We do no shifts, only the Smi conversion, if shift_value is 1.
1380 if (shift_value > 1) {
1381 __ shl(answer.reg(), shift_value - 1);
1382 }
1383 // Convert int result to Smi, checking that it is in int range.
1384 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
1385 __ add(answer.reg(), Operand(answer.reg()));
1386 deferred->enter()->Branch(overflow, operand, not_taken);
1387 operand->Unuse();
1388 deferred->BindExit(&answer);
1389 frame_->Push(&answer);
1390 } else {
1391 deferred->BindExit(operand);
1392 frame_->Push(operand);
1393 }
1394 }
1395 break;
1396 }
1397
1398 case Token::BIT_OR:
1399 case Token::BIT_XOR:
1400 case Token::BIT_AND: {
1401 DeferredCode* deferred = NULL;
1402 if (reversed) {
1403 deferred = new DeferredInlineSmiOperationReversed(this, op, smi_value,
1404 overwrite_mode);
1405 } else {
1406 deferred = new DeferredInlineSmiOperation(this, op, smi_value,
1407 overwrite_mode);
1408 }
1409 operand->ToRegister();
1410 __ test(operand->reg(), Immediate(kSmiTagMask));
1411 deferred->enter()->Branch(not_zero, operand, not_taken);
1412 frame_->Spill(operand->reg());
1413 if (op == Token::BIT_AND) {
1414 __ and_(Operand(operand->reg()), Immediate(value));
1415 } else if (op == Token::BIT_XOR) {
1416 if (int_value != 0) {
1417 __ xor_(Operand(operand->reg()), Immediate(value));
1418 }
1419 } else {
1420 ASSERT(op == Token::BIT_OR);
1421 if (int_value != 0) {
1422 __ or_(Operand(operand->reg()), Immediate(value));
1423 }
1424 }
1425 deferred->BindExit(operand);
1426 frame_->Push(operand);
1427 break;
1428 }
1429
1430 default: {
1431 Result constant_operand(value, this);
1432 if (reversed) {
1433 LikelySmiBinaryOperation(op, &constant_operand, operand,
1434 overwrite_mode);
1435 } else {
1436 LikelySmiBinaryOperation(op, operand, &constant_operand,
1437 overwrite_mode);
1438 }
1439 break;
1440 }
1441 }
1442 ASSERT(!operand->is_valid());
1443 }
1444
1445
1446 class CompareStub: public CodeStub {
1447 public:
1448 CompareStub(Condition cc, bool strict) : cc_(cc), strict_(strict) { }
1449
1450 void Generate(MacroAssembler* masm);
1451
1452 private:
1453 Condition cc_;
1454 bool strict_;
1455
1456 Major MajorKey() { return Compare; }
1457
1458 int MinorKey() {
1459 // Encode the three parameters in a unique 16 bit value.
1460 ASSERT(static_cast<int>(cc_) < (1 << 15));
1461 return (static_cast<int>(cc_) << 1) | (strict_ ? 1 : 0);
1462 }
1463
1464 #ifdef DEBUG
1465 void Print() {
1466 PrintF("CompareStub (cc %d), (strict %s)\n",
1467 static_cast<int>(cc_),
1468 strict_ ? "true" : "false");
1469 }
1470 #endif
1471 };
1472
1473
1474 void CodeGenerator::Comparison(Condition cc,
1475 bool strict,
1476 ControlDestination* dest) {
1477 // Strict only makes sense for equality comparisons.
1478 ASSERT(!strict || cc == equal);
1479
1480 Result left_side(this);
1481 Result right_side(this);
1482 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
1483 if (cc == greater || cc == less_equal) {
1484 cc = ReverseCondition(cc);
1485 left_side = frame_->Pop();
1486 right_side = frame_->Pop();
1487 } else {
1488 right_side = frame_->Pop();
1489 left_side = frame_->Pop();
1490 }
1491 ASSERT(cc == less || cc == equal || cc == greater_equal);
1492
1493 // If either side is a constant smi, optimize the comparison.
1494 bool left_side_constant_smi =
1495 left_side.is_constant() && left_side.handle()->IsSmi();
1496 bool right_side_constant_smi =
1497 right_side.is_constant() && right_side.handle()->IsSmi();
1498 bool left_side_constant_null =
1499 left_side.is_constant() && left_side.handle()->IsNull();
1500 bool right_side_constant_null =
1501 right_side.is_constant() && right_side.handle()->IsNull();
1502
1503 if (left_side_constant_smi || right_side_constant_smi) {
1504 if (left_side_constant_smi && right_side_constant_smi) {
1505 // Trivial case, comparing two constants.
1506 int left_value = Smi::cast(*left_side.handle())->value();
1507 int right_value = Smi::cast(*right_side.handle())->value();
1508 switch (cc) {
1509 case less:
1510 dest->Goto(left_value < right_value);
1511 break;
1512 case equal:
1513 dest->Goto(left_value == right_value);
1514 break;
1515 case greater_equal:
1516 dest->Goto(left_value >= right_value);
1517 break;
1518 default:
1519 UNREACHABLE();
1520 }
1521 } else { // Only one side is a constant Smi.
1522 // If left side is a constant Smi, reverse the operands.
1523 // Since one side is a constant Smi, conversion order does not matter.
1524 if (left_side_constant_smi) {
1525 Result temp = left_side;
1526 left_side = right_side;
1527 right_side = temp;
1528 cc = ReverseCondition(cc);
1529 // This may reintroduce greater or less_equal as the value of cc.
1530 // CompareStub and the inline code both support all values of cc.
1531 }
1532 // Implement comparison against a constant Smi, inlining the case
1533 // where both sides are Smis.
1534 left_side.ToRegister();
1535 ASSERT(left_side.is_valid());
1536 JumpTarget is_smi(this);
1537 __ test(left_side.reg(), Immediate(kSmiTagMask));
1538 is_smi.Branch(zero, &left_side, &right_side, taken);
1539
1540 // Setup and call the compare stub, which expects its arguments
1541 // in registers.
1542 CompareStub stub(cc, strict);
1543 Result result = frame_->CallStub(&stub, &left_side, &right_side);
1544 result.ToRegister();
1545 __ cmp(result.reg(), 0);
1546 result.Unuse();
1547 dest->true_target()->Branch(cc);
1548 dest->false_target()->Jump();
1549
1550 is_smi.Bind(&left_side, &right_side);
1551 left_side.ToRegister();
1552 // Test smi equality and comparison by signed int comparison.
1553 if (IsUnsafeSmi(right_side.handle())) {
1554 right_side.ToRegister();
1555 ASSERT(right_side.is_valid());
1556 __ cmp(left_side.reg(), Operand(right_side.reg()));
1557 } else {
1558 __ cmp(Operand(left_side.reg()), Immediate(right_side.handle()));
1559 }
1560 left_side.Unuse();
1561 right_side.Unuse();
1562 dest->Split(cc);
1563 }
1564 } else if (cc == equal &&
1565 (left_side_constant_null || right_side_constant_null)) {
1566 // To make null checks efficient, we check if either the left side or
1567 // the right side is the constant 'null'.
1568 // If so, we optimize the code by inlining a null check instead of
1569 // calling the (very) general runtime routine for checking equality.
1570 Result operand = left_side_constant_null ? right_side : left_side;
1571 right_side.Unuse();
1572 left_side.Unuse();
1573 operand.ToRegister();
1574 __ cmp(operand.reg(), Factory::null_value());
1575 if (strict) {
1576 operand.Unuse();
1577 dest->Split(equal);
1578 } else {
1579 // The 'null' value is only equal to 'undefined' if using non-strict
1580 // comparisons.
1581 dest->true_target()->Branch(equal);
1582 __ cmp(operand.reg(), Factory::undefined_value());
1583 dest->true_target()->Branch(equal);
1584 __ test(operand.reg(), Immediate(kSmiTagMask));
1585 dest->false_target()->Branch(equal);
1586
1587 // It can be an undetectable object.
1588 // Use a scratch register in preference to spilling operand.reg().
1589 Result temp = allocator()->Allocate();
1590 ASSERT(temp.is_valid());
1591 __ mov(temp.reg(),
1592 FieldOperand(operand.reg(), HeapObject::kMapOffset));
1593 __ movzx_b(temp.reg(),
1594 FieldOperand(temp.reg(), Map::kBitFieldOffset));
1595 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
1596 temp.Unuse();
1597 operand.Unuse();
1598 dest->Split(not_zero);
1599 }
1600 } else { // Neither side is a constant Smi or null.
1601 // If either side is a non-smi constant, skip the smi check.
1602 bool known_non_smi =
1603 (left_side.is_constant() && !left_side.handle()->IsSmi()) ||
1604 (right_side.is_constant() && !right_side.handle()->IsSmi());
1605 left_side.ToRegister();
1606 right_side.ToRegister();
1607 JumpTarget is_smi(this);
1608 if (!known_non_smi) {
1609 // Check for the smi case.
1610 Result temp = allocator_->Allocate();
1611 ASSERT(temp.is_valid());
1612 __ mov(temp.reg(), left_side.reg());
1613 __ or_(temp.reg(), Operand(right_side.reg()));
1614 __ test(temp.reg(), Immediate(kSmiTagMask));
1615 temp.Unuse();
1616 is_smi.Branch(zero, &left_side, &right_side, taken);
1617 }
1618 // When non-smi, call out to the compare stub, which expects its
1619 // arguments in registers.
1620 CompareStub stub(cc, strict);
1621 Result answer = frame_->CallStub(&stub, &left_side, &right_side);
1622 if (cc == equal) {
1623 __ test(answer.reg(), Operand(answer.reg()));
1624 } else {
1625 __ cmp(answer.reg(), 0);
1626 }
1627 answer.Unuse();
1628 if (known_non_smi) {
1629 dest->Split(cc);
1630 } else {
1631 dest->true_target()->Branch(cc);
1632 dest->false_target()->Jump();
1633 is_smi.Bind(&left_side, &right_side);
1634 left_side.ToRegister();
1635 right_side.ToRegister();
1636 __ cmp(left_side.reg(), Operand(right_side.reg()));
1637 right_side.Unuse();
1638 left_side.Unuse();
1639 dest->Split(cc);
1640 }
1641 }
1642 }
1643
1644
1645 class CallFunctionStub: public CodeStub {
1646 public:
1647 explicit CallFunctionStub(int argc) : argc_(argc) { }
1648
1649 void Generate(MacroAssembler* masm);
1650
1651 private:
1652 int argc_;
1653
1654 #ifdef DEBUG
1655 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); }
1656 #endif
1657
1658 Major MajorKey() { return CallFunction; }
1659 int MinorKey() { return argc_; }
1660 };
1661
1662
1663 // Call the function just below TOS on the stack with the given
1664 // arguments. The receiver is the TOS.
1665 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
1666 int position) {
1667 // Push the arguments ("left-to-right") on the stack.
1668 int arg_count = args->length();
1669 for (int i = 0; i < arg_count; i++) {
1670 Load(args->at(i));
1671 }
1672
1673 // Record the position for debugging purposes.
1674 CodeForSourcePosition(position);
1675
1676 // Use the shared code stub to call the function.
1677 CallFunctionStub call_function(arg_count);
1678 Result answer = frame_->CallStub(&call_function, arg_count + 1);
1679 // Restore context and replace function on the stack with the
1680 // result of the stub invocation.
1681 frame_->RestoreContextRegister();
1682 frame_->SetElementAt(0, &answer);
1683 }
1684
1685
1686 class DeferredStackCheck: public DeferredCode {
1687 public:
1688 explicit DeferredStackCheck(CodeGenerator* generator)
1689 : DeferredCode(generator) {
1690 set_comment("[ DeferredStackCheck");
1691 }
1692
1693 virtual void Generate();
1694 };
1695
1696
1697 void DeferredStackCheck::Generate() {
1698 enter()->Bind();
1699 StackCheckStub stub;
1700 Result ignored = generator()->frame()->CallStub(&stub, 0);
1701 ignored.Unuse();
1702 exit_.Jump();
1703 }
1704
1705
1706 void CodeGenerator::CheckStack() {
1707 if (FLAG_check_stack) {
1708 DeferredStackCheck* deferred = new DeferredStackCheck(this);
1709 ExternalReference stack_guard_limit =
1710 ExternalReference::address_of_stack_guard_limit();
1711 __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
1712 deferred->enter()->Branch(below, not_taken);
1713 deferred->BindExit();
1714 }
1715 }
1716
1717
1718 void CodeGenerator::VisitAndSpill(Statement* statement) {
1719 ASSERT(in_spilled_code());
1720 set_in_spilled_code(false);
1721 Visit(statement);
1722 if (frame_ != NULL) {
1723 frame_->SpillAll();
1724 }
1725 set_in_spilled_code(true);
1726 }
1727
1728
1729 void CodeGenerator::VisitStatementsAndSpill(ZoneList<Statement*>* statements) {
1730 ASSERT(in_spilled_code());
1731 set_in_spilled_code(false);
1732 VisitStatements(statements);
1733 if (frame_ != NULL) {
1734 frame_->SpillAll();
1735 }
1736 set_in_spilled_code(true);
1737 }
1738
1739
1740 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
1741 ASSERT(!in_spilled_code());
1742 for (int i = 0; has_valid_frame() && i < statements->length(); i++) {
1743 Visit(statements->at(i));
1744 }
1745 }
1746
1747
1748 void CodeGenerator::VisitBlock(Block* node) {
1749 ASSERT(!in_spilled_code());
1750 Comment cmnt(masm_, "[ Block");
1751 CodeForStatementPosition(node);
1752 node->break_target()->Initialize(this);
1753 VisitStatements(node->statements());
1754 if (node->break_target()->is_linked()) {
1755 node->break_target()->Bind();
1756 }
1757 node->break_target()->Unuse();
1758 }
1759
1760
1761 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
1762 frame_->Push(pairs);
1763
1764 // Duplicate the context register.
1765 Result context(esi, this);
1766 frame_->Push(&context);
1767
1768 frame_->Push(Smi::FromInt(is_eval() ? 1 : 0));
1769 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
1770 // Return value is ignored.
1771 }
1772
1773
1774 void CodeGenerator::VisitDeclaration(Declaration* node) {
1775 Comment cmnt(masm_, "[ Declaration");
1776 CodeForStatementPosition(node);
1777 Variable* var = node->proxy()->var();
1778 ASSERT(var != NULL); // must have been resolved
1779 Slot* slot = var->slot();
1780
1781 // If it was not possible to allocate the variable at compile time,
1782 // we need to "declare" it at runtime to make sure it actually
1783 // exists in the local context.
1784 if (slot != NULL && slot->type() == Slot::LOOKUP) {
1785 // Variables with a "LOOKUP" slot were introduced as non-locals
1786 // during variable resolution and must have mode DYNAMIC.
1787 ASSERT(var->is_dynamic());
1788 // For now, just do a runtime call. Duplicate the context register.
1789 Result context(esi, this);
1790 frame_->Push(&context);
1791 frame_->Push(var->name());
1792 // Declaration nodes are always introduced in one of two modes.
1793 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
1794 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
1795 frame_->Push(Smi::FromInt(attr));
1796 // Push initial value, if any.
1797 // Note: For variables we must not push an initial value (such as
1798 // 'undefined') because we may have a (legal) redeclaration and we
1799 // must not destroy the current value.
1800 if (node->mode() == Variable::CONST) {
1801 frame_->Push(Factory::the_hole_value());
1802 } else if (node->fun() != NULL) {
1803 Load(node->fun());
1804 } else {
1805 frame_->Push(Smi::FromInt(0)); // no initial value!
1806 }
1807 Result ignored = frame_->CallRuntime(Runtime::kDeclareContextSlot, 4);
1808 // Ignore the return value (declarations are statements).
1809 return;
1810 }
1811
1812 ASSERT(!var->is_global());
1813
1814 // If we have a function or a constant, we need to initialize the variable.
1815 Expression* val = NULL;
1816 if (node->mode() == Variable::CONST) {
1817 val = new Literal(Factory::the_hole_value());
1818 } else {
1819 val = node->fun(); // NULL if we don't have a function
1820 }
1821
1822 if (val != NULL) {
1823 {
1824 // Set the initial value.
1825 Reference target(this, node->proxy());
1826 Load(val);
1827 target.SetValue(NOT_CONST_INIT);
1828 // The reference is removed from the stack (preserving TOS) when
1829 // it goes out of scope.
1830 }
1831 // Get rid of the assigned value (declarations are statements).
1832 frame_->Drop();
1833 }
1834 }
1835
1836
1837 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
1838 ASSERT(!in_spilled_code());
1839 Comment cmnt(masm_, "[ ExpressionStatement");
1840 CodeForStatementPosition(node);
1841 Expression* expression = node->expression();
1842 expression->MarkAsStatement();
1843 Load(expression);
1844 // Remove the lingering expression result from the top of stack.
1845 frame_->Drop();
1846 }
1847
1848
1849 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
1850 ASSERT(!in_spilled_code());
1851 Comment cmnt(masm_, "// EmptyStatement");
1852 CodeForStatementPosition(node);
1853 // nothing to do
1854 }
1855
1856
1857 void CodeGenerator::VisitIfStatement(IfStatement* node) {
1858 ASSERT(!in_spilled_code());
1859 Comment cmnt(masm_, "[ IfStatement");
1860 // Generate different code depending on which parts of the if statement
1861 // are present or not.
1862 bool has_then_stm = node->HasThenStatement();
1863 bool has_else_stm = node->HasElseStatement();
1864
1865 CodeForStatementPosition(node);
1866 JumpTarget exit(this);
1867 if (has_then_stm && has_else_stm) {
1868 JumpTarget then(this);
1869 JumpTarget else_(this);
1870 ControlDestination dest(&then, &else_, true);
1871 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
1872
1873 if (dest.false_was_fall_through()) {
1874 // The else target was bound, so we compile the else part first.
1875 Visit(node->else_statement());
1876
1877 // We may have dangling jumps to the then part.
1878 if (then.is_linked()) {
1879 if (has_valid_frame()) exit.Jump();
1880 then.Bind();
1881 Visit(node->then_statement());
1882 }
1883 } else {
1884 // The then target was bound, so we compile the then part first.
1885 Visit(node->then_statement());
1886
1887 if (else_.is_linked()) {
1888 if (has_valid_frame()) exit.Jump();
1889 else_.Bind();
1890 Visit(node->else_statement());
1891 }
1892 }
1893
1894 } else if (has_then_stm) {
1895 ASSERT(!has_else_stm);
1896 JumpTarget then(this);
1897 ControlDestination dest(&then, &exit, true);
1898 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
1899
1900 if (dest.false_was_fall_through()) {
1901 // The exit label was bound. We may have dangling jumps to the
1902 // then part.
1903 if (then.is_linked()) {
1904 exit.Unuse();
1905 exit.Jump();
1906 then.Bind();
1907 Visit(node->then_statement());
1908 }
1909 } else {
1910 // The then label was bound.
1911 Visit(node->then_statement());
1912 }
1913
1914 } else if (has_else_stm) {
1915 ASSERT(!has_then_stm);
1916 JumpTarget else_(this);
1917 ControlDestination dest(&exit, &else_, false);
1918 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
1919
1920 if (dest.true_was_fall_through()) {
1921 // The exit label was bound. We may have dangling jumps to the
1922 // else part.
1923 if (else_.is_linked()) {
1924 exit.Unuse();
1925 exit.Jump();
1926 else_.Bind();
1927 Visit(node->else_statement());
1928 }
1929 } else {
1930 // The else label was bound.
1931 Visit(node->else_statement());
1932 }
1933
1934 } else {
1935 ASSERT(!has_then_stm && !has_else_stm);
1936 // We only care about the condition's side effects (not its value
1937 // or control flow effect). LoadCondition is called without
1938 // forcing control flow.
1939 ControlDestination dest(&exit, &exit, true);
1940 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, false);
1941 if (!dest.is_used()) {
1942 // We got a value on the frame rather than (or in addition to)
1943 // control flow.
1944 frame_->Drop();
1945 }
1946 }
1947
1948 if (exit.is_linked()) {
1949 exit.Bind();
1950 }
1951 }
1952
1953
1954 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
1955 ASSERT(!in_spilled_code());
1956 Comment cmnt(masm_, "[ ContinueStatement");
1957 CodeForStatementPosition(node);
1958 node->target()->continue_target()->Jump();
1959 }
1960
1961
1962 void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
1963 ASSERT(!in_spilled_code());
1964 Comment cmnt(masm_, "[ BreakStatement");
1965 CodeForStatementPosition(node);
1966 node->target()->break_target()->Jump();
1967 }
1968
1969
1970 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
1971 ASSERT(!in_spilled_code());
1972 Comment cmnt(masm_, "[ ReturnStatement");
1973
1974 CodeForStatementPosition(node);
1975 Load(node->expression());
1976 Result return_value = frame_->Pop();
1977 if (function_return_is_shadowed_) {
1978 function_return_.Jump(&return_value);
1979 } else {
1980 frame_->PrepareForReturn();
1981 if (function_return_.is_bound()) {
1982 // If the function return label is already bound we reuse the
1983 // code by jumping to the return site.
1984 function_return_.Jump(&return_value);
1985 } else {
1986 // Though this is a (possibly) backward block, the frames can
1987 // only differ on their top element.
1988 function_return_.Bind(&return_value, 1);
1989 GenerateReturnSequence(&return_value);
1990 }
1991 }
1992 }
1993
1994
1995 void CodeGenerator::GenerateReturnSequence(Result* return_value) {
1996 // The return value is a live (but not currently reference counted)
1997 // reference to eax. This is safe because the current frame does not
1998 // contain a reference to eax (it is prepared for the return by spilling
1999 // all registers).
2000 if (FLAG_trace) {
2001 frame_->Push(return_value);
2002 *return_value = frame_->CallRuntime(Runtime::kTraceExit, 1);
2003 }
2004 return_value->ToRegister(eax);
2005
2006 // Add a label for checking the size of the code used for returning.
2007 Label check_exit_codesize;
2008 masm_->bind(&check_exit_codesize);
2009
2010 // Leave the frame and return popping the arguments and the
2011 // receiver.
2012 frame_->Exit();
2013 masm_->ret((scope_->num_parameters() + 1) * kPointerSize);
2014 DeleteFrame();
2015
2016 // Check that the size of the code used for returning matches what is
2017 // expected by the debugger.
2018 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
2019 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
2020 }
2021
2022
2023 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
2024 ASSERT(!in_spilled_code());
2025 Comment cmnt(masm_, "[ WithEnterStatement");
2026 CodeForStatementPosition(node);
2027 Load(node->expression());
2028 Result context(this);
2029 if (node->is_catch_block()) {
2030 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1);
2031 } else {
2032 context = frame_->CallRuntime(Runtime::kPushContext, 1);
2033 }
2034
2035 // Update context local.
2036 frame_->SaveContextRegister();
2037
2038 // Verify that the runtime call result and esi agree.
2039 if (FLAG_debug_code) {
2040 __ cmp(context.reg(), Operand(esi));
2041 __ Assert(equal, "Runtime::NewContext should end up in esi");
2042 }
2043 }
2044
2045
2046 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
2047 ASSERT(!in_spilled_code());
2048 Comment cmnt(masm_, "[ WithExitStatement");
2049 CodeForStatementPosition(node);
2050 // Pop context.
2051 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX));
2052 // Update context local.
2053 frame_->SaveContextRegister();
2054 }
2055
2056
2057 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
2058 return kFastSwitchMaxOverheadFactor;
2059 }
2060
2061
2062 int CodeGenerator::FastCaseSwitchMinCaseCount() {
2063 return kFastSwitchMinCaseCount;
2064 }
2065
2066
2067 // Generate a computed jump to a switch case.
2068 void CodeGenerator::GenerateFastCaseSwitchJumpTable(
2069 SwitchStatement* node,
2070 int min_index,
2071 int range,
2072 Label* default_label,
2073 Vector<Label*> case_targets,
2074 Vector<Label> case_labels) {
2075 // Notice: Internal references, used by both the jmp instruction and
2076 // the table entries, need to be relocated if the buffer grows. This
2077 // prevents the forward use of Labels, since a displacement cannot
2078 // survive relocation, and it also cannot safely be distinguished
2079 // from a real address. Instead we put in zero-values as
2080 // placeholders, and fill in the addresses after the labels have been
2081 // bound.
2082
2083 JumpTarget setup_default(this);
2084 JumpTarget is_smi(this);
2085
2086 // A non-null default label pointer indicates a default case among
2087 // the case labels. Otherwise we use the break target as a
2088 // "default".
2089 JumpTarget* default_target =
2090 (default_label == NULL) ? node->break_target() : &setup_default;
2091
2092 // Test whether input is a smi.
2093 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
2094 Result switch_value = frame_->Pop();
2095 switch_value.ToRegister();
2096 __ test(switch_value.reg(), Immediate(kSmiTagMask));
2097 is_smi.Branch(equal, &switch_value, taken);
2098
2099 // It's a heap object, not a smi or a failure. Check if it is a
2100 // heap number.
2101 Result temp = allocator()->Allocate();
2102 ASSERT(temp.is_valid());
2103 __ CmpObjectType(switch_value.reg(), HEAP_NUMBER_TYPE, temp.reg());
2104 temp.Unuse();
2105 default_target->Branch(not_equal);
2106
2107 // The switch value is a heap number. Convert it to a smi.
2108 frame_->Push(&switch_value);
2109 Result smi_value = frame_->CallRuntime(Runtime::kNumberToSmi, 1);
2110
2111 is_smi.Bind(&smi_value);
2112 smi_value.ToRegister();
2113 // Convert the switch value to a 0-based table index.
2114 if (min_index != 0) {
2115 frame_->Spill(smi_value.reg());
2116 __ sub(Operand(smi_value.reg()), Immediate(min_index << kSmiTagSize));
2117 }
2118 // Go to the default case if the table index is negative or not a smi.
2119 __ test(smi_value.reg(), Immediate(0x80000000 | kSmiTagMask));
2120 default_target->Branch(not_equal, not_taken);
2121 __ cmp(smi_value.reg(), range << kSmiTagSize);
2122 default_target->Branch(greater_equal, not_taken);
2123
2124 // The expected frame at all the case labels is a version of the
2125 // current one (the bidirectional entry frame, which an arbitrary
2126 // frame of the correct height can be merged to). Keep a copy to
2127 // restore at the start of every label. Create a jump target and
2128 // bind it to set its entry frame properly.
2129 JumpTarget entry_target(this, JumpTarget::BIDIRECTIONAL);
2130 entry_target.Bind(&smi_value);
2131 VirtualFrame* start_frame = new VirtualFrame(frame_);
2132
2133 // 0 is placeholder.
2134 // Jump to the address at table_address + 2 * smi_value.reg().
2135 // The target of the jump is read from table_address + 4 * switch_value.
2136 // The Smi encoding of smi_value.reg() is 2 * switch_value.
2137 smi_value.ToRegister();
2138 __ jmp(Operand(smi_value.reg(), smi_value.reg(),
2139 times_1, 0x0, RelocInfo::INTERNAL_REFERENCE));
2140 smi_value.Unuse();
2141 // Calculate address to overwrite later with actual address of table.
2142 int32_t jump_table_ref = masm_->pc_offset() - sizeof(int32_t);
2143 __ Align(4);
2144 Label table_start;
2145 __ bind(&table_start);
2146 __ WriteInternalReference(jump_table_ref, table_start);
2147
2148 for (int i = 0; i < range; i++) {
2149 // These are the table entries. 0x0 is the placeholder for case address.
2150 __ dd(0x0, RelocInfo::INTERNAL_REFERENCE);
2151 }
2152
2153 GenerateFastCaseSwitchCases(node, case_labels, start_frame);
2154
2155 // If there was a default case, we need to emit the code to match it.
2156 if (default_label != NULL) {
2157 if (has_valid_frame()) {
2158 node->break_target()->Jump();
2159 }
2160 setup_default.Bind();
2161 frame_->MergeTo(start_frame);
2162 __ jmp(default_label);
2163 DeleteFrame();
2164 }
2165 if (node->break_target()->is_linked()) {
2166 node->break_target()->Bind();
2167 }
2168
2169 for (int i = 0, entry_pos = table_start.pos();
2170 i < range;
2171 i++, entry_pos += sizeof(uint32_t)) {
2172 if (case_targets[i] == NULL) {
2173 __ WriteInternalReference(entry_pos,
2174 *node->break_target()->entry_label());
2175 } else {
2176 __ WriteInternalReference(entry_pos, *case_targets[i]);
2177 }
2178 }
2179
2180 delete start_frame;
2181 }
2182
2183
2184 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
2185 ASSERT(!in_spilled_code());
2186 Comment cmnt(masm_, "[ SwitchStatement");
2187 CodeForStatementPosition(node);
2188 node->break_target()->Initialize(this);
2189
2190 // Compile the switch value.
2191 Load(node->tag());
2192
2193 if (TryGenerateFastCaseSwitchStatement(node)) {
2194 return;
2195 }
2196
2197 ZoneList<CaseClause*>* cases = node->cases();
2198 int length = cases->length();
2199 CaseClause* default_clause = NULL;
2200
2201 JumpTarget next_test(this);
2202 // Compile the case label expressions and comparisons. Exit early
2203 // if a comparison is unconditionally true. The target next_test is
2204 // bound before the loop in order to indicate control flow to the
2205 // first comparison.
2206 next_test.Bind();
2207 for (int i = 0; i < length && !next_test.is_unused(); i++) {
2208 CaseClause* clause = cases->at(i);
2209 clause->body_target()->Initialize(this);
2210 // The default is not a test, but remember it for later.
2211 if (clause->is_default()) {
2212 default_clause = clause;
2213 continue;
2214 }
2215
2216 Comment cmnt(masm_, "[ Case comparison");
2217 // We recycle the same target next_test for each test. Bind it if
2218 // the previous test has not done so and then unuse it for the
2219 // loop.
2220 if (next_test.is_linked()) {
2221 next_test.Bind();
2222 }
2223 next_test.Unuse();
2224
2225 // Duplicate the switch value.
2226 frame_->Dup();
2227
2228 // Compile the label expression.
2229 Load(clause->label());
2230
2231 // Compare and branch to the body if true or the next test if
2232 // false. Prefer the next test as a fall through.
2233 ControlDestination dest(clause->body_target(), &next_test, false);
2234 Comparison(equal, true, &dest);
2235
2236 // If the comparison fell through to the true target, jump to the
2237 // actual body.
2238 if (dest.true_was_fall_through()) {
2239 clause->body_target()->Unuse();
2240 clause->body_target()->Jump();
2241 }
2242 }
2243
2244 // If there was control flow to a next test from the last one
2245 // compiled, compile a jump to the default or break target.
2246 if (!next_test.is_unused()) {
2247 if (next_test.is_linked()) {
2248 next_test.Bind();
2249 }
2250 // Drop the switch value.
2251 frame_->Drop();
2252 if (default_clause != NULL) {
2253 default_clause->body_target()->Jump();
2254 } else {
2255 node->break_target()->Jump();
2256 }
2257 }
2258
2259
2260 // The last instruction emitted was a jump, either to the default
2261 // clause or the break target, or else to a case body from the loop
2262 // that compiles the tests.
2263 ASSERT(!has_valid_frame());
2264 // Compile case bodies as needed.
2265 for (int i = 0; i < length; i++) {
2266 CaseClause* clause = cases->at(i);
2267
2268 // There are two ways to reach the body: from the corresponding
2269 // test or as the fall through of the previous body.
2270 if (clause->body_target()->is_linked() || has_valid_frame()) {
2271 if (clause->body_target()->is_linked()) {
2272 if (has_valid_frame()) {
2273 // If we have both a jump to the test and a fall through, put
2274 // a jump on the fall through path to avoid the dropping of
2275 // the switch value on the test path. The exception is the
2276 // default which has already had the switch value dropped.
2277 if (clause->is_default()) {
2278 clause->body_target()->Bind();
2279 } else {
2280 JumpTarget body(this);
2281 body.Jump();
2282 clause->body_target()->Bind();
2283 frame_->Drop();
2284 body.Bind();
2285 }
2286 } else {
2287 // No fall through to worry about.
2288 clause->body_target()->Bind();
2289 if (!clause->is_default()) {
2290 frame_->Drop();
2291 }
2292 }
2293 } else {
2294 // Otherwise, we have only fall through.
2295 ASSERT(has_valid_frame());
2296 }
2297
2298 // We are now prepared to compile the body.
2299 Comment cmnt(masm_, "[ Case body");
2300 VisitStatements(clause->statements());
2301 }
2302 clause->body_target()->Unuse();
2303 }
2304
2305 // We may not have a valid frame here so bind the break target only
2306 // if needed.
2307 if (node->break_target()->is_linked()) {
2308 node->break_target()->Bind();
2309 }
2310 node->break_target()->Unuse();
2311 }
2312
2313
2314 void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
2315 ASSERT(!in_spilled_code());
2316 Comment cmnt(masm_, "[ LoopStatement");
2317 CodeForStatementPosition(node);
2318 node->break_target()->Initialize(this);
2319
2320 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a
2321 // known result for the test expression, with no side effects.
2322 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
2323 if (node->cond() == NULL) {
2324 ASSERT(node->type() == LoopStatement::FOR_LOOP);
2325 info = ALWAYS_TRUE;
2326 } else {
2327 Literal* lit = node->cond()->AsLiteral();
2328 if (lit != NULL) {
2329 if (lit->IsTrue()) {
2330 info = ALWAYS_TRUE;
2331 } else if (lit->IsFalse()) {
2332 info = ALWAYS_FALSE;
2333 }
2334 }
2335 }
2336
2337 switch (node->type()) {
2338 case LoopStatement::DO_LOOP: {
2339 JumpTarget body(this, JumpTarget::BIDIRECTIONAL);
2340 IncrementLoopNesting();
2341
2342 // Label the top of the loop for the backward jump if necessary.
2343 if (info == ALWAYS_TRUE) {
2344 // Use the continue target.
2345 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
2346 node->continue_target()->Bind();
2347 } else if (info == ALWAYS_FALSE) {
2348 // No need to label it.
2349 node->continue_target()->Initialize(this);
2350 } else {
2351 // Continue is the test, so use the backward body target.
2352 ASSERT(info == DONT_KNOW);
2353 node->continue_target()->Initialize(this);
2354 body.Bind();
2355 }
2356
2357 CheckStack(); // TODO(1222600): ignore if body contains calls.
2358 Visit(node->body());
2359
2360 // Compile the test.
2361 if (info == ALWAYS_TRUE) {
2362 // If control flow can fall off the end of the body, jump back
2363 // to the top and bind the break target at the exit.
2364 if (has_valid_frame()) {
2365 node->continue_target()->Jump();
2366 }
2367 if (node->break_target()->is_linked()) {
2368 node->break_target()->Bind();
2369 }
2370
2371 } else if (info == ALWAYS_FALSE) {
2372 // We may have had continues or breaks in the body.
2373 if (node->continue_target()->is_linked()) {
2374 node->continue_target()->Bind();
2375 }
2376 if (node->break_target()->is_linked()) {
2377 node->break_target()->Bind();
2378 }
2379
2380 } else {
2381 ASSERT(info == DONT_KNOW);
2382 // We have to compile the test expression if it can be reached by
2383 // control flow falling out of the body or via continue.
2384 if (node->continue_target()->is_linked()) {
2385 node->continue_target()->Bind();
2386 }
2387 if (has_valid_frame()) {
2388 ControlDestination dest(&body, node->break_target(), false);
2389 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
2390 }
2391 if (node->break_target()->is_linked()) {
2392 node->break_target()->Bind();
2393 }
2394 }
2395 break;
2396 }
2397
2398 case LoopStatement::WHILE_LOOP: {
2399 // Do not duplicate conditions that may have function literal
2400 // subexpressions. This can cause us to compile the function
2401 // literal twice.
2402 bool test_at_bottom = !node->may_have_function_literal();
2403
2404 IncrementLoopNesting();
2405
2406 // If the condition is always false and has no side effects, we
2407 // do not need to compile anything.
2408 if (info == ALWAYS_FALSE) break;
2409
2410 JumpTarget body;
2411 if (test_at_bottom) {
2412 body.Initialize(this, JumpTarget::BIDIRECTIONAL);
2413 } else {
2414 body.Initialize(this);
2415 }
2416
2417 // Based on the condition analysis, compile the test as necessary.
2418 if (info == ALWAYS_TRUE) {
2419 // We will not compile the test expression. Label the top of
2420 // the loop with the continue target.
2421 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
2422 node->continue_target()->Bind();
2423 } else {
2424 ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here.
2425 if (test_at_bottom) {
2426 // Continue is the test at the bottom, no need to label the
2427 // test at the top. The body is a backward target.
2428 node->continue_target()->Initialize(this);
2429 } else {
2430 // Label the test at the top as the continue target. The
2431 // body is a forward-only target.
2432 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
2433 node->continue_target()->Bind();
2434 }
2435 // Compile the test with the body as the true target and
2436 // preferred fall-through and with the break target as the
2437 // false target.
2438 ControlDestination dest(&body, node->break_target(), true);
2439 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
2440
2441 if (dest.false_was_fall_through()) {
2442 // If we got the break target as fall-through, the test may
2443 // have been unconditionally false (if there are no jumps to
2444 // the body).
2445 if (!body.is_linked()) break;
2446
2447 // Otherwise, jump around the body on the fall through and
2448 // then bind the body target.
2449 node->break_target()->Unuse();
2450 node->break_target()->Jump();
2451 body.Bind();
2452 }
2453 }
2454
2455 CheckStack(); // TODO(1222600): ignore if body contains calls.
2456 Visit(node->body());
2457
2458 // Based on the condition analysis, compile the backward jump as
2459 // necessary.
2460 if (info == ALWAYS_TRUE) {
2461 // The loop body has been labeled with the continue target.
2462 if (has_valid_frame()) {
2463 node->continue_target()->Jump();
2464 }
2465 } else {
2466 ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here.
2467 if (test_at_bottom) {
2468 // If we have chosen to recompile the test at the bottom,
2469 // then it is the continue target.
2470 if (node->continue_target()->is_linked()) {
2471 node->continue_target()->Bind();
2472 }
2473 if (has_valid_frame()) {
2474 // The break target is the fall-through (body is a backward
2475 // jump from here and thus an invalid fall-through).
2476 ControlDestination dest(&body, node->break_target(), false);
2477 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
2478 }
2479 } else {
2480 // If we have chosen not to recompile the test at the
2481 // bottom, jump back to the one at the top.
2482 if (has_valid_frame()) {
2483 node->continue_target()->Jump();
2484 }
2485 }
2486 }
2487
2488 // The break target may be already bound (by the condition), or
2489 // there may not be a valid frame. Bind it only if needed.
2490 if (node->break_target()->is_linked()) {
2491 node->break_target()->Bind();
2492 }
2493 break;
2494 }
2495
2496 case LoopStatement::FOR_LOOP: {
2497 // Do not duplicate conditions that may have function literal
2498 // subexpressions. This can cause us to compile the function
2499 // literal twice.
2500 bool test_at_bottom = !node->may_have_function_literal();
2501
2502 // Compile the init expression if present.
2503 if (node->init() != NULL) {
2504 Visit(node->init());
2505 }
2506
2507 IncrementLoopNesting();
2508
2509 // If the condition is always false and has no side effects, we
2510 // do not need to compile anything else.
2511 if (info == ALWAYS_FALSE) break;
2512
2513 // Target for backward edge if no test at the bottom, otherwise
2514 // unused.
2515 JumpTarget loop(this, JumpTarget::BIDIRECTIONAL);
2516
2517 // Target for backward edge if there is a test at the bottom,
2518 // otherwise used as target for test at the top.
2519 JumpTarget body;
2520 if (test_at_bottom) {
2521 body.Initialize(this, JumpTarget::BIDIRECTIONAL);
2522 } else {
2523 body.Initialize(this);
2524 }
2525
2526 // Based on the condition analysis, compile the test as necessary.
2527 if (info == ALWAYS_TRUE) {
2528 // We will not compile the test expression. Label the top of
2529 // the loop.
2530 if (node->next() == NULL) {
2531 // Use the continue target if there is no update expression.
2532 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
2533 node->continue_target()->Bind();
2534 } else {
2535 // Otherwise use the backward loop target.
2536 node->continue_target()->Initialize(this);
2537 loop.Bind();
2538 }
2539 } else {
2540 ASSERT(info == DONT_KNOW);
2541 if (test_at_bottom) {
2542 // Continue is either the update expression or the test at
2543 // the bottom, no need to label the test at the top.
2544 node->continue_target()->Initialize(this);
2545 } else if (node->next() == NULL) {
2546 // We are not recompiling the test at the bottom and there
2547 // is no update expression.
2548 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
2549 node->continue_target()->Bind();
2550 } else {
2551 // We are not recompiling the test at the bottom and there
2552 // is an update expression.
2553 node->continue_target()->Initialize(this);
2554 loop.Bind();
2555 }
2556
2557 // Compile the test with the body as the true target and
2558 // preferred fall-through and with the break target as the
2559 // false target.
2560 ControlDestination dest(&body, node->break_target(), true);
2561 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
2562
2563 if (dest.false_was_fall_through()) {
2564 // If we got the break target as fall-through, the test may
2565 // have been unconditionally false (if there are no jumps to
2566 // the body).
2567 if (!body.is_linked()) break;
2568
2569 // Otherwise, jump around the body on the fall through and
2570 // then bind the body target.
2571 node->break_target()->Unuse();
2572 node->break_target()->Jump();
2573 body.Bind();
2574 }
2575 }
2576
2577 CheckStack(); // TODO(1222600): ignore if body contains calls.
2578 Visit(node->body());
2579
2580 // If there is an update expression, compile it if necessary.
2581 if (node->next() != NULL) {
2582 if (node->continue_target()->is_linked()) {
2583 node->continue_target()->Bind();
2584 }
2585
2586 // Control can reach the update by falling out of the body or
2587 // by a continue.
2588 if (has_valid_frame()) {
2589 // Record the source position of the statement as this code
2590 // which is after the code for the body actually belongs to
2591 // the loop statement and not the body.
2592 CodeForStatementPosition(node);
2593 Visit(node->next());
2594 }
2595 }
2596
2597 // Based on the condition analysis, compile the backward jump as
2598 // necessary.
2599 if (info == ALWAYS_TRUE) {
2600 if (has_valid_frame()) {
2601 if (node->next() == NULL) {
2602 node->continue_target()->Jump();
2603 } else {
2604 loop.Jump();
2605 }
2606 }
2607 } else {
2608 ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here.
2609 if (test_at_bottom) {
2610 if (node->continue_target()->is_linked()) {
2611 // We can have dangling jumps to the continue target if
2612 // there was no update expression.
2613 node->continue_target()->Bind();
2614 }
2615 // Control can reach the test at the bottom by falling out
2616 // of the body, by a continue in the body, or from the
2617 // update expression.
2618 if (has_valid_frame()) {
2619 // The break target is the fall-through (body is a
2620 // backward jump from here).
2621 ControlDestination dest(&body, node->break_target(), false);
2622 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
2623 }
2624 } else {
2625 // Otherwise, jump back to the test at the top.
2626 if (has_valid_frame()) {
2627 if (node->next() == NULL) {
2628 node->continue_target()->Jump();
2629 } else {
2630 loop.Jump();
2631 }
2632 }
2633 }
2634 }
2635
2636 // The break target may be already bound (by the condition), or
2637 // there may not be a valid frame. Bind it only if needed.
2638 if (node->break_target()->is_linked()) {
2639 node->break_target()->Bind();
2640 }
2641 break;
2642 }
2643 }
2644
2645 DecrementLoopNesting();
2646 node->continue_target()->Unuse();
2647 node->break_target()->Unuse();
2648 }
2649
2650
2651 void CodeGenerator::VisitForInStatement(ForInStatement* node) {
2652 ASSERT(!in_spilled_code());
2653 VirtualFrame::SpilledScope spilled_scope(this);
2654 Comment cmnt(masm_, "[ ForInStatement");
2655 CodeForStatementPosition(node);
2656
2657 JumpTarget primitive(this);
2658 JumpTarget jsobject(this);
2659 JumpTarget fixed_array(this);
2660 JumpTarget entry(this, JumpTarget::BIDIRECTIONAL);
2661 JumpTarget end_del_check(this);
2662 JumpTarget exit(this);
2663
2664 // Get the object to enumerate over (converted to JSObject).
2665 LoadAndSpill(node->enumerable());
2666
2667 // Both SpiderMonkey and kjs ignore null and undefined in contrast
2668 // to the specification. 12.6.4 mandates a call to ToObject.
2669 frame_->EmitPop(eax);
2670
2671 // eax: value to be iterated over
2672 __ cmp(eax, Factory::undefined_value());
2673 exit.Branch(equal);
2674 __ cmp(eax, Factory::null_value());
2675 exit.Branch(equal);
2676
2677 // Stack layout in body:
2678 // [iteration counter (smi)] <- slot 0
2679 // [length of array] <- slot 1
2680 // [FixedArray] <- slot 2
2681 // [Map or 0] <- slot 3
2682 // [Object] <- slot 4
2683
2684 // Check if enumerable is already a JSObject
2685 // eax: value to be iterated over
2686 __ test(eax, Immediate(kSmiTagMask));
2687 primitive.Branch(zero);
2688 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
2689 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
2690 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
2691 jsobject.Branch(above_equal);
2692
2693 primitive.Bind();
2694 frame_->EmitPush(eax);
2695 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1);
2696 // function call returns the value in eax, which is where we want it below
2697
2698 jsobject.Bind();
2699 // Get the set of properties (as a FixedArray or Map).
2700 // eax: value to be iterated over
2701 frame_->EmitPush(eax); // push the object being iterated over (slot 4)
2702
2703 frame_->EmitPush(eax); // push the Object (slot 4) for the runtime call
2704 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
2705
2706 // If we got a Map, we can do a fast modification check.
2707 // Otherwise, we got a FixedArray, and we have to do a slow check.
2708 // eax: map or fixed array (result from call to
2709 // Runtime::kGetPropertyNamesFast)
2710 __ mov(edx, Operand(eax));
2711 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
2712 __ cmp(ecx, Factory::meta_map());
2713 fixed_array.Branch(not_equal);
2714
2715 // Get enum cache
2716 // eax: map (result from call to Runtime::kGetPropertyNamesFast)
2717 __ mov(ecx, Operand(eax));
2718 __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset));
2719 // Get the bridge array held in the enumeration index field.
2720 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
2721 // Get the cache from the bridge array.
2722 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
2723
2724 frame_->EmitPush(eax); // <- slot 3
2725 frame_->EmitPush(edx); // <- slot 2
2726 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
2727 __ shl(eax, kSmiTagSize);
2728 frame_->EmitPush(eax); // <- slot 1
2729 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0
2730 entry.Jump();
2731
2732 fixed_array.Bind();
2733 // eax: fixed array (result from call to Runtime::kGetPropertyNamesFast)
2734 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 3
2735 frame_->EmitPush(eax); // <- slot 2
2736
2737 // Push the length of the array and the initial index onto the stack.
2738 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
2739 __ shl(eax, kSmiTagSize);
2740 frame_->EmitPush(eax); // <- slot 1
2741 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0
2742
2743 // Condition.
2744 entry.Bind();
2745 // Grab the current frame's height for the break and continue
2746 // targets only after all the state is pushed on the frame.
2747 node->break_target()->Initialize(this);
2748 node->continue_target()->Initialize(this);
2749
2750 __ mov(eax, frame_->ElementAt(0)); // load the current count
2751 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length
2752 node->break_target()->Branch(above_equal);
2753
2754 // Get the i'th entry of the array.
2755 __ mov(edx, frame_->ElementAt(2));
2756 __ mov(ebx, Operand(edx, eax, times_2,
2757 FixedArray::kHeaderSize - kHeapObjectTag));
2758
2759 // Get the expected map from the stack or a zero map in the
2760 // permanent slow case eax: current iteration count ebx: i'th entry
2761 // of the enum cache
2762 __ mov(edx, frame_->ElementAt(3));
2763 // Check if the expected map still matches that of the enumerable.
2764 // If not, we have to filter the key.
2765 // eax: current iteration count
2766 // ebx: i'th entry of the enum cache
2767 // edx: expected map value
2768 __ mov(ecx, frame_->ElementAt(4));
2769 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2770 __ cmp(ecx, Operand(edx));
2771 end_del_check.Branch(equal);
2772
2773 // Convert the entry to a string (or null if it isn't a property anymore).
2774 frame_->EmitPush(frame_->ElementAt(4)); // push enumerable
2775 frame_->EmitPush(ebx); // push entry
2776 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2);
2777 __ mov(ebx, Operand(eax));
2778
2779 // If the property has been removed while iterating, we just skip it.
2780 __ cmp(ebx, Factory::null_value());
2781 node->continue_target()->Branch(equal);
2782
2783 end_del_check.Bind();
2784 // Store the entry in the 'each' expression and take another spin in the
2785 // loop. edx: i'th entry of the enum cache (or string there of)
2786 frame_->EmitPush(ebx);
2787 { Reference each(this, node->each());
2788 // Loading a reference may leave the frame in an unspilled state.
2789 frame_->SpillAll();
2790 if (!each.is_illegal()) {
2791 if (each.size() > 0) {
2792 frame_->EmitPush(frame_->ElementAt(each.size()));
2793 }
2794 // If the reference was to a slot we rely on the convenient property
2795 // that it doesn't matter whether a value (eg, ebx pushed above) is
2796 // right on top of or right underneath a zero-sized reference.
2797 each.SetValue(NOT_CONST_INIT);
2798 if (each.size() > 0) {
2799 // It's safe to pop the value lying on top of the reference before
2800 // unloading the reference itself (which preserves the top of stack,
2801 // ie, now the topmost value of the non-zero sized reference), since
2802 // we will discard the top of stack after unloading the reference
2803 // anyway.
2804 frame_->Drop();
2805 }
2806 }
2807 }
2808 // Unloading a reference may leave the frame in an unspilled state.
2809 frame_->SpillAll();
2810
2811 // Discard the i'th entry pushed above or else the remainder of the
2812 // reference, whichever is currently on top of the stack.
2813 frame_->Drop();
2814
2815 // Body.
2816 CheckStack(); // TODO(1222600): ignore if body contains calls.
2817 VisitAndSpill(node->body());
2818
2819 // Next. Reestablish a spilled frame in case we are coming here via
2820 // a continue in the body.
2821 node->continue_target()->Bind();
2822 frame_->SpillAll();
2823 frame_->EmitPop(eax);
2824 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
2825 frame_->EmitPush(eax);
2826 entry.Jump();
2827
2828 // Cleanup. No need to spill because VirtualFrame::Drop is safe for
2829 // any frame.
2830 node->break_target()->Bind();
2831 frame_->Drop(5);
2832
2833 // Exit.
2834 exit.Bind();
2835
2836 node->continue_target()->Unuse();
2837 node->break_target()->Unuse();
2838 }
2839
2840
2841 void CodeGenerator::VisitTryCatch(TryCatch* node) {
2842 ASSERT(!in_spilled_code());
2843 VirtualFrame::SpilledScope spilled_scope(this);
2844 Comment cmnt(masm_, "[ TryCatch");
2845 CodeForStatementPosition(node);
2846
2847 JumpTarget try_block(this);
2848 JumpTarget exit(this);
2849
2850 try_block.Call();
2851 // --- Catch block ---
2852 frame_->EmitPush(eax);
2853
2854 // Store the caught exception in the catch variable.
2855 { Reference ref(this, node->catch_var());
2856 ASSERT(ref.is_slot());
2857 // Load the exception to the top of the stack. Here we make use of the
2858 // convenient property that it doesn't matter whether a value is
2859 // immediately on top of or underneath a zero-sized reference.
2860 ref.SetValue(NOT_CONST_INIT);
2861 }
2862
2863 // Remove the exception from the stack.
2864 frame_->Drop();
2865
2866 VisitStatementsAndSpill(node->catch_block()->statements());
2867 if (has_valid_frame()) {
2868 exit.Jump();
2869 }
2870
2871
2872 // --- Try block ---
2873 try_block.Bind();
2874
2875 frame_->PushTryHandler(TRY_CATCH_HANDLER);
2876 int handler_height = frame_->height();
2877
2878 // Shadow the jump targets for all escapes from the try block, including
2879 // returns. During shadowing, the original target is hidden as the
2880 // ShadowTarget and operations on the original actually affect the
2881 // shadowing target.
2882 //
2883 // We should probably try to unify the escaping targets and the return
2884 // target.
2885 int nof_escapes = node->escaping_targets()->length();
2886 List<ShadowTarget*> shadows(1 + nof_escapes);
2887
2888 // Add the shadow target for the function return.
2889 static const int kReturnShadowIndex = 0;
2890 shadows.Add(new ShadowTarget(&function_return_));
2891 bool function_return_was_shadowed = function_return_is_shadowed_;
2892 function_return_is_shadowed_ = true;
2893 ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_);
2894
2895 // Add the remaining shadow targets.
2896 for (int i = 0; i < nof_escapes; i++) {
2897 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
2898 }
2899
2900 // Generate code for the statements in the try block.
2901 VisitStatementsAndSpill(node->try_block()->statements());
2902
2903 // Stop the introduced shadowing and count the number of required unlinks.
2904 // After shadowing stops, the original targets are unshadowed and the
2905 // ShadowTargets represent the formerly shadowing targets.
2906 bool has_unlinks = false;
2907 for (int i = 0; i < shadows.length(); i++) {
2908 shadows[i]->StopShadowing();
2909 has_unlinks = has_unlinks || shadows[i]->is_linked();
2910 }
2911 function_return_is_shadowed_ = function_return_was_shadowed;
2912
2913 // Get an external reference to the handler address.
2914 ExternalReference handler_address(Top::k_handler_address);
2915
2916 // Make sure that there's nothing left on the stack above the
2917 // handler structure.
2918 if (FLAG_debug_code) {
2919 __ mov(eax, Operand::StaticVariable(handler_address));
2920 __ lea(eax, Operand(eax, StackHandlerConstants::kAddressDisplacement));
2921 __ cmp(esp, Operand(eax));
2922 __ Assert(equal, "stack pointer should point to top handler");
2923 }
2924
2925 // If we can fall off the end of the try block, unlink from try chain.
2926 if (has_valid_frame()) {
2927 // The next handler address is on top of the frame. Unlink from
2928 // the handler list and drop the rest of this handler from the
2929 // frame.
2930 frame_->EmitPop(Operand::StaticVariable(handler_address));
2931 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2932 if (has_unlinks) {
2933 exit.Jump();
2934 }
2935 }
2936
2937 // Generate unlink code for the (formerly) shadowing targets that
2938 // have been jumped to. Deallocate each shadow target.
2939 Result return_value(this);
2940 for (int i = 0; i < shadows.length(); i++) {
2941 if (shadows[i]->is_linked()) {
2942 // Unlink from try chain; be careful not to destroy the TOS if
2943 // there is one.
2944 if (i == kReturnShadowIndex) {
2945 shadows[i]->Bind(&return_value);
2946 return_value.ToRegister(eax);
2947 } else {
2948 shadows[i]->Bind();
2949 }
2950 // Because we can be jumping here (to spilled code) from
2951 // unspilled code, we need to reestablish a spilled frame at
2952 // this block.
2953 frame_->SpillAll();
2954
2955 // Reload sp from the top handler, because some statements that we
2956 // break from (eg, for...in) may have left stuff on the stack.
2957 __ mov(edx, Operand::StaticVariable(handler_address));
2958 const int kNextOffset = StackHandlerConstants::kNextOffset +
2959 StackHandlerConstants::kAddressDisplacement;
2960 __ lea(esp, Operand(edx, kNextOffset));
2961 frame_->Forget(frame_->height() - handler_height);
2962
2963 frame_->EmitPop(Operand::StaticVariable(handler_address));
2964 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2965 // next_sp popped.
2966
2967 if (i == kReturnShadowIndex) {
2968 if (!function_return_is_shadowed_) frame_->PrepareForReturn();
2969 shadows[i]->other_target()->Jump(&return_value);
2970 } else {
2971 shadows[i]->other_target()->Jump();
2972 }
2973 }
2974 delete shadows[i];
2975 }
2976
2977 exit.Bind();
2978 }
2979
2980
2981 void CodeGenerator::VisitTryFinally(TryFinally* node) {
2982 ASSERT(!in_spilled_code());
2983 VirtualFrame::SpilledScope spilled_scope(this);
2984 Comment cmnt(masm_, "[ TryFinally");
2985 CodeForStatementPosition(node);
2986
2987 // State: Used to keep track of reason for entering the finally
2988 // block. Should probably be extended to hold information for
2989 // break/continue from within the try block.
2990 enum { FALLING, THROWING, JUMPING };
2991
2992 JumpTarget try_block(this);
2993 JumpTarget finally_block(this);
2994
2995 try_block.Call();
2996
2997 frame_->EmitPush(eax);
2998 // In case of thrown exceptions, this is where we continue.
2999 __ Set(ecx, Immediate(Smi::FromInt(THROWING)));
3000 finally_block.Jump();
3001
3002 // --- Try block ---
3003 try_block.Bind();
3004
3005 frame_->PushTryHandler(TRY_FINALLY_HANDLER);
3006 int handler_height = frame_->height();
3007
3008 // Shadow the jump targets for all escapes from the try block, including
3009 // returns. During shadowing, the original target is hidden as the
3010 // ShadowTarget and operations on the original actually affect the
3011 // shadowing target.
3012 //
3013 // We should probably try to unify the escaping targets and the return
3014 // target.
3015 int nof_escapes = node->escaping_targets()->length();
3016 List<ShadowTarget*> shadows(1 + nof_escapes);
3017
3018 // Add the shadow target for the function return.
3019 static const int kReturnShadowIndex = 0;
3020 shadows.Add(new ShadowTarget(&function_return_));
3021 bool function_return_was_shadowed = function_return_is_shadowed_;
3022 function_return_is_shadowed_ = true;
3023 ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_);
3024
3025 // Add the remaining shadow targets.
3026 for (int i = 0; i < nof_escapes; i++) {
3027 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
3028 }
3029
3030 // Generate code for the statements in the try block.
3031 VisitStatementsAndSpill(node->try_block()->statements());
3032
3033 // Stop the introduced shadowing and count the number of required unlinks.
3034 // After shadowing stops, the original targets are unshadowed and the
3035 // ShadowTargets represent the formerly shadowing targets.
3036 int nof_unlinks = 0;
3037 for (int i = 0; i < shadows.length(); i++) {
3038 shadows[i]->StopShadowing();
3039 if (shadows[i]->is_linked()) nof_unlinks++;
3040 }
3041 function_return_is_shadowed_ = function_return_was_shadowed;
3042
3043 // Get an external reference to the handler address.
3044 ExternalReference handler_address(Top::k_handler_address);
3045
3046 // If we can fall off the end of the try block, unlink from the try
3047 // chain and set the state on the frame to FALLING.
3048 if (has_valid_frame()) {
3049 // The next handler address is on top of the frame.
3050 ASSERT(StackHandlerConstants::kNextOffset == 0);
3051 frame_->EmitPop(eax);
3052 __ mov(Operand::StaticVariable(handler_address), eax);
3053 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
3054
3055 // Fake a top of stack value (unneeded when FALLING) and set the
3056 // state in ecx, then jump around the unlink blocks if any.
3057 frame_->EmitPush(Immediate(Factory::undefined_value()));
3058 __ Set(ecx, Immediate(Smi::FromInt(FALLING)));
3059 if (nof_unlinks > 0) {
3060 finally_block.Jump();
3061 }
3062 }
3063
3064 // Generate code to unlink and set the state for the (formerly)
3065 // shadowing targets that have been jumped to.
3066 for (int i = 0; i < shadows.length(); i++) {
3067 if (shadows[i]->is_linked()) {
3068 // If we have come from the shadowed return, the return value is
3069 // on the virtual frame. We must preserve it until it is
3070 // pushed.
3071 if (i == kReturnShadowIndex) {
3072 Result return_value(this);
3073 shadows[i]->Bind(&return_value);
3074 return_value.ToRegister(eax);
3075 } else {
3076 shadows[i]->Bind();
3077 }
3078 // Because we can be jumping here (to spilled code) from
3079 // unspilled code, we need to reestablish a spilled frame at
3080 // this block.
3081 frame_->SpillAll();
3082
3083 // Reload sp from the top handler, because some statements that
3084 // we break from (eg, for...in) may have left stuff on the
3085 // stack.
3086 __ mov(edx, Operand::StaticVariable(handler_address));
3087 const int kNextOffset = StackHandlerConstants::kNextOffset +
3088 StackHandlerConstants::kAddressDisplacement;
3089 __ lea(esp, Operand(edx, kNextOffset));
3090 frame_->Forget(frame_->height() - handler_height);
3091
3092 // Unlink this handler and drop it from the frame.
3093 frame_->EmitPop(Operand::StaticVariable(handler_address));
3094 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
3095
3096 if (i == kReturnShadowIndex) {
3097 // If this target shadowed the function return, materialize
3098 // the return value on the stack.
3099 frame_->EmitPush(eax);
3100 } else {
3101 // Fake TOS for targets that shadowed breaks and continues.
3102 frame_->EmitPush(Immediate(Factory::undefined_value()));
3103 }
3104 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i)));
3105 if (--nof_unlinks > 0) {
3106 // If this is not the last unlink block, jump around the next.
3107 finally_block.Jump();
3108 }
3109 }
3110 }
3111
3112 // --- Finally block ---
3113 finally_block.Bind();
3114
3115 // Push the state on the stack.
3116 frame_->EmitPush(ecx);
3117
3118 // We keep two elements on the stack - the (possibly faked) result
3119 // and the state - while evaluating the finally block.
3120 //
3121 // Generate code for the statements in the finally block.
3122 VisitStatementsAndSpill(node->finally_block()->statements());
3123
3124 if (has_valid_frame()) {
3125 // Restore state and return value or faked TOS.
3126 frame_->EmitPop(ecx);
3127 frame_->EmitPop(eax);
3128 }
3129
3130 // Generate code to jump to the right destination for all used
3131 // formerly shadowing targets. Deallocate each shadow target.
3132 for (int i = 0; i < shadows.length(); i++) {
3133 if (has_valid_frame() && shadows[i]->is_bound()) {
3134 BreakTarget* original = shadows[i]->other_target();
3135 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i)));
3136 if (i == kReturnShadowIndex) {
3137 // The return value is (already) in eax.
3138 Result return_value = allocator_->Allocate(eax);
3139 ASSERT(return_value.is_valid());
3140 if (function_return_is_shadowed_) {
3141 original->Branch(equal, &return_value);
3142 } else {
3143 // Branch around the preparation for return which may emit
3144 // code.
3145 JumpTarget skip(this);
3146 skip.Branch(not_equal);
3147 frame_->PrepareForReturn();
3148 original->Jump(&return_value);
3149 skip.Bind();
3150 }
3151 } else {
3152 original->Branch(equal);
3153 }
3154 }
3155 delete shadows[i];
3156 }
3157
3158 if (has_valid_frame()) {
3159 // Check if we need to rethrow the exception.
3160 JumpTarget exit(this);
3161 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING)));
3162 exit.Branch(not_equal);
3163
3164 // Rethrow exception.
3165 frame_->EmitPush(eax); // undo pop from above
3166 frame_->CallRuntime(Runtime::kReThrow, 1);
3167
3168 // Done.
3169 exit.Bind();
3170 }
3171 }
3172
3173
3174 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
3175 ASSERT(!in_spilled_code());
3176 Comment cmnt(masm_, "[ DebuggerStatement");
3177 CodeForStatementPosition(node);
3178 #ifdef ENABLE_DEBUGGER_SUPPORT
3179 // Spill everything, even constants, to the frame.
3180 frame_->SpillAll();
3181 frame_->CallRuntime(Runtime::kDebugBreak, 0);
3182 // Ignore the return value.
3183 #endif
3184 }
3185
3186
3187 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
3188 ASSERT(boilerplate->IsBoilerplate());
3189
3190 // Push the boilerplate on the stack.
3191 frame_->Push(boilerplate);
3192
3193 // Create a new closure.
3194 frame_->Push(esi);
3195 Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
3196 frame_->Push(&result);
3197 }
3198
3199
3200 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
3201 Comment cmnt(masm_, "[ FunctionLiteral");
3202
3203 // Build the function boilerplate and instantiate it.
3204 Handle<JSFunction> boilerplate = BuildBoilerplate(node);
3205 // Check for stack-overflow exception.
3206 if (HasStackOverflow()) return;
3207 InstantiateBoilerplate(boilerplate);
3208 }
3209
3210
3211 void CodeGenerator::VisitFunctionBoilerplateLiteral(
3212 FunctionBoilerplateLiteral* node) {
3213 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
3214 InstantiateBoilerplate(node->boilerplate());
3215 }
3216
3217
3218 void CodeGenerator::VisitConditional(Conditional* node) {
3219 Comment cmnt(masm_, "[ Conditional");
3220 JumpTarget then(this);
3221 JumpTarget else_(this);
3222 JumpTarget exit(this);
3223 ControlDestination dest(&then, &else_, true);
3224 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
3225
3226 if (dest.false_was_fall_through()) {
3227 // The else target was bound, so we compile the else part first.
3228 Load(node->else_expression(), typeof_state());
3229
3230 if (then.is_linked()) {
3231 exit.Jump();
3232 then.Bind();
3233 Load(node->then_expression(), typeof_state());
3234 }
3235 } else {
3236 // The then target was bound, so we compile the then part first.
3237 Load(node->then_expression(), typeof_state());
3238
3239 if (else_.is_linked()) {
3240 exit.Jump();
3241 else_.Bind();
3242 Load(node->else_expression(), typeof_state());
3243 }
3244 }
3245
3246 exit.Bind();
3247 }
3248
3249
3250 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
3251 if (slot->type() == Slot::LOOKUP) {
3252 ASSERT(slot->var()->is_dynamic());
3253
3254 JumpTarget slow(this);
3255 JumpTarget done(this);
3256 Result value(this);
3257
3258 // Generate fast-case code for variables that might be shadowed by
3259 // eval-introduced variables. Eval is used a lot without
3260 // introducing variables. In those cases, we do not want to
3261 // perform a runtime call for all variables in the scope
3262 // containing the eval.
3263 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
3264 value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow);
3265 // If there was no control flow to slow, we can exit early.
3266 if (!slow.is_linked()) {
3267 frame_->Push(&value);
3268 return;
3269 }
3270
3271 done.Jump(&value);
3272
3273 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
3274 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
3275 // Only generate the fast case for locals that rewrite to slots.
3276 // This rules out argument loads.
3277 if (potential_slot != NULL) {
3278 // Allocate a fresh register to use as a temp in
3279 // ContextSlotOperandCheckExtensions and to hold the result
3280 // value.
3281 value = allocator_->Allocate();
3282 ASSERT(value.is_valid());
3283 __ mov(value.reg(),
3284 ContextSlotOperandCheckExtensions(potential_slot,
3285 value,
3286 &slow));
3287 if (potential_slot->var()->mode() == Variable::CONST) {
3288 __ cmp(value.reg(), Factory::the_hole_value());
3289 done.Branch(not_equal, &value);
3290 __ mov(value.reg(), Factory::undefined_value());
3291 }
3292 // There is always control flow to slow from
3293 // ContextSlotOperandCheckExtensions so we have to jump around
3294 // it.
3295 done.Jump(&value);
3296 }
3297 }
3298
3299 slow.Bind();
3300 frame_->Push(esi);
3301 frame_->Push(slot->var()->name());
3302 if (typeof_state == INSIDE_TYPEOF) {
3303 value =
3304 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
3305 } else {
3306 value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
3307 }
3308
3309 done.Bind(&value);
3310 frame_->Push(&value);
3311
3312 } else if (slot->var()->mode() == Variable::CONST) {
3313 // Const slots may contain 'the hole' value (the constant hasn't been
3314 // initialized yet) which needs to be converted into the 'undefined'
3315 // value.
3316 //
3317 // We currently spill the virtual frame because constants use the
3318 // potentially unsafe direct-frame access of SlotOperand.
3319 VirtualFrame::SpilledScope spilled_scope(this);
3320 Comment cmnt(masm_, "[ Load const");
3321 JumpTarget exit(this);
3322 __ mov(ecx, SlotOperand(slot, ecx));
3323 __ cmp(ecx, Factory::the_hole_value());
3324 exit.Branch(not_equal);
3325 __ mov(ecx, Factory::undefined_value());
3326 exit.Bind();
3327 frame_->EmitPush(ecx);
3328
3329 } else if (slot->type() == Slot::PARAMETER) {
3330 frame_->PushParameterAt(slot->index());
3331
3332 } else if (slot->type() == Slot::LOCAL) {
3333 frame_->PushLocalAt(slot->index());
3334
3335 } else {
3336 // The other remaining slot types (LOOKUP and GLOBAL) cannot reach
3337 // here.
3338 //
3339 // The use of SlotOperand below is safe for an unspilled frame
3340 // because it will always be a context slot.
3341 ASSERT(slot->type() == Slot::CONTEXT);
3342 Result temp = allocator_->Allocate();
3343 ASSERT(temp.is_valid());
3344 __ mov(temp.reg(), SlotOperand(slot, temp.reg()));
3345 frame_->Push(&temp);
3346 }
3347 }
3348
3349
3350 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
3351 Slot* slot,
3352 TypeofState typeof_state,
3353 JumpTarget* slow) {
3354 // Check that no extension objects have been created by calls to
3355 // eval from the current scope to the global scope.
3356 Result context(esi, this);
3357 Result tmp = allocator_->Allocate();
3358 ASSERT(tmp.is_valid()); // All non-reserved registers were available.
3359
3360 Scope* s = scope();
3361 while (s != NULL) {
3362 if (s->num_heap_slots() > 0) {
3363 if (s->calls_eval()) {
3364 // Check that extension is NULL.
3365 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX),
3366 Immediate(0));
3367 slow->Branch(not_equal, not_taken);
3368 }
3369 // Load next context in chain.
3370 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::CLOSURE_INDEX));
3371 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset));
3372 context = tmp;
3373 }
3374 // If no outer scope calls eval, we do not need to check more
3375 // context extensions. If we have reached an eval scope, we check
3376 // all extensions from this point.
3377 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
3378 s = s->outer_scope();
3379 }
3380
3381 if (s->is_eval_scope()) {
3382 // Loop up the context chain. There is no frame effect so it is
3383 // safe to use raw labels here.
3384 Label next, fast;
3385 if (!context.reg().is(tmp.reg())) {
3386 __ mov(tmp.reg(), context.reg());
3387 }
3388 __ bind(&next);
3389 // Terminate at global context.
3390 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset),
3391 Immediate(Factory::global_context_map()));
3392 __ j(equal, &fast);
3393 // Check that extension is NULL.
3394 __ cmp(ContextOperand(tmp.reg(), Context::EXTENSION_INDEX), Immediate(0));
3395 slow->Branch(not_equal, not_taken);
3396 // Load next context in chain.
3397 __ mov(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX));
3398 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset));
3399 __ jmp(&next);
3400 __ bind(&fast);
3401 }
3402 context.Unuse();
3403 tmp.Unuse();
3404
3405 // All extension objects were empty and it is safe to use a global
3406 // load IC call.
3407 LoadGlobal();
3408 frame_->Push(slot->var()->name());
3409 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
3410 ? RelocInfo::CODE_TARGET
3411 : RelocInfo::CODE_TARGET_CONTEXT;
3412 Result answer = frame_->CallLoadIC(mode);
3413
3414 // Discard the global object. The result is in answer.
3415 frame_->Drop();
3416 return answer;
3417 }
3418
3419
3420 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
3421 if (slot->type() == Slot::LOOKUP) {
3422 ASSERT(slot->var()->is_dynamic());
3423
3424 // For now, just do a runtime call.
3425 frame_->Push(esi);
3426 frame_->Push(slot->var()->name());
3427
3428 Result value(this);
3429 if (init_state == CONST_INIT) {
3430 // Same as the case for a normal store, but ignores attribute
3431 // (e.g. READ_ONLY) of context slot so that we can initialize const
3432 // properties (introduced via eval("const foo = (some expr);")). Also,
3433 // uses the current function context instead of the top context.
3434 //
3435 // Note that we must declare the foo upon entry of eval(), via a
3436 // context slot declaration, but we cannot initialize it at the same
3437 // time, because the const declaration may be at the end of the eval
3438 // code (sigh...) and the const variable may have been used before
3439 // (where its value is 'undefined'). Thus, we can only do the
3440 // initialization when we actually encounter the expression and when
3441 // the expression operands are defined and valid, and thus we need the
3442 // split into 2 operations: declaration of the context slot followed
3443 // by initialization.
3444 value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
3445 } else {
3446 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3);
3447 }
3448 // Storing a variable must keep the (new) value on the expression
3449 // stack. This is necessary for compiling chained assignment
3450 // expressions.
3451 frame_->Push(&value);
3452
3453 } else {
3454 ASSERT(!slot->var()->is_dynamic());
3455
3456 JumpTarget exit(this);
3457 if (init_state == CONST_INIT) {
3458 ASSERT(slot->var()->mode() == Variable::CONST);
3459 // Only the first const initialization must be executed (the slot
3460 // still contains 'the hole' value). When the assignment is executed,
3461 // the code is identical to a normal store (see below).
3462 //
3463 // We spill the frame in the code below because the direct-frame
3464 // access of SlotOperand is potentially unsafe with an unspilled
3465 // frame.
3466 VirtualFrame::SpilledScope spilled_scope(this);
3467 Comment cmnt(masm_, "[ Init const");
3468 __ mov(ecx, SlotOperand(slot, ecx));
3469 __ cmp(ecx, Factory::the_hole_value());
3470 exit.Branch(not_equal);
3471 }
3472
3473 // We must execute the store. Storing a variable must keep the (new)
3474 // value on the stack. This is necessary for compiling assignment
3475 // expressions.
3476 //
3477 // Note: We will reach here even with slot->var()->mode() ==
3478 // Variable::CONST because of const declarations which will initialize
3479 // consts to 'the hole' value and by doing so, end up calling this code.
3480 if (slot->type() == Slot::PARAMETER) {
3481 frame_->StoreToParameterAt(slot->index());
3482 } else if (slot->type() == Slot::LOCAL) {
3483 frame_->StoreToLocalAt(slot->index());
3484 } else {
3485 // The other slot types (LOOKUP and GLOBAL) cannot reach here.
3486 //
3487 // The use of SlotOperand below is safe for an unspilled frame
3488 // because the slot is a context slot.
3489 ASSERT(slot->type() == Slot::CONTEXT);
3490 frame_->Dup();
3491 Result value = frame_->Pop();
3492 value.ToRegister();
3493 Result start = allocator_->Allocate();
3494 ASSERT(start.is_valid());
3495 __ mov(SlotOperand(slot, start.reg()), value.reg());
3496 // RecordWrite may destroy the value registers.
3497 //
3498 // TODO(204): Avoid actually spilling when the value is not
3499 // needed (probably the common case).
3500 frame_->Spill(value.reg());
3501 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
3502 Result temp = allocator_->Allocate();
3503 ASSERT(temp.is_valid());
3504 __ RecordWrite(start.reg(), offset, value.reg(), temp.reg());
3505 // The results start, value, and temp are unused by going out of
3506 // scope.
3507 }
3508
3509 exit.Bind();
3510 }
3511 }
3512
3513
3514 void CodeGenerator::VisitSlot(Slot* node) {
3515 Comment cmnt(masm_, "[ Slot");
3516 LoadFromSlot(node, typeof_state());
3517 }
3518
3519
3520 void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
3521 Comment cmnt(masm_, "[ VariableProxy");
3522 Variable* var = node->var();
3523 Expression* expr = var->rewrite();
3524 if (expr != NULL) {
3525 Visit(expr);
3526 } else {
3527 ASSERT(var->is_global());
3528 Reference ref(this, node);
3529 ref.GetValue(typeof_state());
3530 }
3531 }
3532
3533
3534 void CodeGenerator::VisitLiteral(Literal* node) {
3535 Comment cmnt(masm_, "[ Literal");
3536 frame_->Push(node->handle());
3537 }
3538
3539
3540 void CodeGenerator::LoadUnsafeSmi(Register target, Handle<Object> value) {
3541 ASSERT(target.is_valid());
3542 ASSERT(value->IsSmi());
3543 int bits = reinterpret_cast<int>(*value);
3544 __ Set(target, Immediate(bits & 0x0000FFFF));
3545 __ xor_(target, bits & 0xFFFF0000);
3546 }
3547
3548
3549 bool CodeGenerator::IsUnsafeSmi(Handle<Object> value) {
3550 if (!value->IsSmi()) return false;
3551 int int_value = Smi::cast(*value)->value();
3552 return !is_intn(int_value, kMaxSmiInlinedBits);
3553 }
3554
3555
3556 class DeferredRegExpLiteral: public DeferredCode {
3557 public:
3558 DeferredRegExpLiteral(CodeGenerator* generator, RegExpLiteral* node)
3559 : DeferredCode(generator), node_(node) {
3560 set_comment("[ DeferredRegExpLiteral");
3561 }
3562
3563 virtual void Generate();
3564
3565 private:
3566 RegExpLiteral* node_;
3567 };
3568
3569
3570 void DeferredRegExpLiteral::Generate() {
3571 Result literals(generator());
3572 enter()->Bind(&literals);
3573 // Since the entry is undefined we call the runtime system to
3574 // compute the literal.
3575
3576 VirtualFrame* frame = generator()->frame();
3577 // Literal array (0).
3578 frame->Push(&literals);
3579 // Literal index (1).
3580 frame->Push(Smi::FromInt(node_->literal_index()));
3581 // RegExp pattern (2).
3582 frame->Push(node_->pattern());
3583 // RegExp flags (3).
3584 frame->Push(node_->flags());
3585 Result boilerplate =
3586 frame->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
3587 exit_.Jump(&boilerplate);
3588 }
3589
3590
3591 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
3592 Comment cmnt(masm_, "[ RegExp Literal");
3593 DeferredRegExpLiteral* deferred = new DeferredRegExpLiteral(this, node);
3594
3595 // Retrieve the literals array and check the allocated entry. Begin
3596 // with a writable copy of the function of this activation in a
3597 // register.
3598 frame_->PushFunction();
3599 Result literals = frame_->Pop();
3600 literals.ToRegister();
3601 frame_->Spill(literals.reg());
3602
3603 // Load the literals array of the function.
3604 __ mov(literals.reg(),
3605 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
3606
3607 // Load the literal at the ast saved index.
3608 int literal_offset =
3609 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
3610 Result boilerplate = allocator_->Allocate();
3611 ASSERT(boilerplate.is_valid());
3612 __ mov(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset));
3613
3614 // Check whether we need to materialize the RegExp object. If so,
3615 // jump to the deferred code passing the literals array.
3616 __ cmp(boilerplate.reg(), Factory::undefined_value());
3617 deferred->enter()->Branch(equal, &literals, not_taken);
3618
3619 literals.Unuse();
3620 // The deferred code returns the boilerplate object.
3621 deferred->BindExit(&boilerplate);
3622
3623 // Push the boilerplate object.
3624 frame_->Push(&boilerplate);
3625 }
3626
3627
3628 // This deferred code stub will be used for creating the boilerplate
3629 // by calling Runtime_CreateObjectLiteral.
3630 // Each created boilerplate is stored in the JSFunction and they are
3631 // therefore context dependent.
3632 class DeferredObjectLiteral: public DeferredCode {
3633 public:
3634 DeferredObjectLiteral(CodeGenerator* generator,
3635 ObjectLiteral* node)
3636 : DeferredCode(generator), node_(node) {
3637 set_comment("[ DeferredObjectLiteral");
3638 }
3639
3640 virtual void Generate();
3641
3642 private:
3643 ObjectLiteral* node_;
3644 };
3645
3646
3647 void DeferredObjectLiteral::Generate() {
3648 Result literals(generator());
3649 enter()->Bind(&literals);
3650 // Since the entry is undefined we call the runtime system to
3651 // compute the literal.
3652
3653 VirtualFrame* frame = generator()->frame();
3654 // Literal array (0).
3655 frame->Push(&literals);
3656 // Literal index (1).
3657 frame->Push(Smi::FromInt(node_->literal_index()));
3658 // Constant properties (2).
3659 frame->Push(node_->constant_properties());
3660 Result boilerplate =
3661 frame->CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
3662 exit_.Jump(&boilerplate);
3663 }
3664
3665
3666 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
3667 Comment cmnt(masm_, "[ ObjectLiteral");
3668 DeferredObjectLiteral* deferred = new DeferredObjectLiteral(this, node);
3669
3670 // Retrieve the literals array and check the allocated entry. Begin
3671 // with a writable copy of the function of this activation in a
3672 // register.
3673 frame_->PushFunction();
3674 Result literals = frame_->Pop();
3675 literals.ToRegister();
3676 frame_->Spill(literals.reg());
3677
3678 // Load the literals array of the function.
3679 __ mov(literals.reg(),
3680 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
3681
3682 // Load the literal at the ast saved index.
3683 int literal_offset =
3684 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
3685 Result boilerplate = allocator_->Allocate();
3686 ASSERT(boilerplate.is_valid());
3687 __ mov(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset));
3688
3689 // Check whether we need to materialize the object literal boilerplate.
3690 // If so, jump to the deferred code passing the literals array.
3691 __ cmp(boilerplate.reg(), Factory::undefined_value());
3692 deferred->enter()->Branch(equal, &literals, not_taken);
3693
3694 literals.Unuse();
3695 // The deferred code returns the boilerplate object.
3696 deferred->BindExit(&boilerplate);
3697
3698 // Push the boilerplate object.
3699 frame_->Push(&boilerplate);
3700 // Clone the boilerplate object.
3701 Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate;
3702 if (node->depth() == 1) {
3703 clone_function_id = Runtime::kCloneShallowLiteralBoilerplate;
3704 }
3705 Result clone = frame_->CallRuntime(clone_function_id, 1);
3706 // Push the newly cloned literal object as the result.
3707 frame_->Push(&clone);
3708
3709 for (int i = 0; i < node->properties()->length(); i++) {
3710 ObjectLiteral::Property* property = node->properties()->at(i);
3711 switch (property->kind()) {
3712 case ObjectLiteral::Property::CONSTANT:
3713 break;
3714 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
3715 if (CompileTimeValue::IsCompileTimeValue(property->value())) break;
3716 // else fall through.
3717 case ObjectLiteral::Property::COMPUTED: {
3718 Handle<Object> key(property->key()->handle());
3719 if (key->IsSymbol()) {
3720 // Duplicate the object as the IC receiver.
3721 frame_->Dup();
3722 Load(property->value());
3723 frame_->Push(key);
3724 Result ignored = frame_->CallStoreIC();
3725 // Drop the duplicated receiver and ignore the result.
3726 frame_->Drop();
3727 break;
3728 }
3729 // Fall through
3730 }
3731 case ObjectLiteral::Property::PROTOTYPE: {
3732 // Duplicate the object as an argument to the runtime call.
3733 frame_->Dup();
3734 Load(property->key());
3735 Load(property->value());
3736 Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3);
3737 // Ignore the result.
3738 break;
3739 }
3740 case ObjectLiteral::Property::SETTER: {
3741 // Duplicate the object as an argument to the runtime call.
3742 frame_->Dup();
3743 Load(property->key());
3744 frame_->Push(Smi::FromInt(1));
3745 Load(property->value());
3746 Result ignored = frame_->CallRuntime(Runtime::kDefineAccessor, 4);
3747 // Ignore the result.
3748 break;
3749 }
3750 case ObjectLiteral::Property::GETTER: {
3751 // Duplicate the object as an argument to the runtime call.
3752 frame_->Dup();
3753 Load(property->key());
3754 frame_->Push(Smi::FromInt(0));
3755 Load(property->value());
3756 Result ignored = frame_->CallRuntime(Runtime::kDefineAccessor, 4);
3757 // Ignore the result.
3758 break;
3759 }
3760 default: UNREACHABLE();
3761 }
3762 }
3763 }
3764
3765
3766 // This deferred code stub will be used for creating the boilerplate
3767 // by calling Runtime_CreateArrayLiteralBoilerplate.
3768 // Each created boilerplate is stored in the JSFunction and they are
3769 // therefore context dependent.
3770 class DeferredArrayLiteral: public DeferredCode {
3771 public:
3772 DeferredArrayLiteral(CodeGenerator* generator,
3773 ArrayLiteral* node)
3774 : DeferredCode(generator), node_(node) {
3775 set_comment("[ DeferredArrayLiteral");
3776 }
3777
3778 virtual void Generate();
3779
3780 private:
3781 ArrayLiteral* node_;
3782 };
3783
3784
3785 void DeferredArrayLiteral::Generate() {
3786 Result literals(generator());
3787 enter()->Bind(&literals);
3788 // Since the entry is undefined we call the runtime system to
3789 // compute the literal.
3790
3791 VirtualFrame* frame = generator()->frame();
3792 // Literal array (0).
3793 frame->Push(&literals);
3794 // Literal index (1).
3795 frame->Push(Smi::FromInt(node_->literal_index()));
3796 // Constant properties (2).
3797 frame->Push(node_->literals());
3798 Result boilerplate =
3799 frame->CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
3800 exit_.Jump(&boilerplate);
3801 }
3802
3803
3804 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
3805 Comment cmnt(masm_, "[ ArrayLiteral");
3806 DeferredArrayLiteral* deferred = new DeferredArrayLiteral(this, node);
3807
3808 // Retrieve the literals array and check the allocated entry. Begin
3809 // with a writable copy of the function of this activation in a
3810 // register.
3811 frame_->PushFunction();
3812 Result literals = frame_->Pop();
3813 literals.ToRegister();
3814 frame_->Spill(literals.reg());
3815
3816 // Load the literals array of the function.
3817 __ mov(literals.reg(),
3818 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
3819
3820 // Load the literal at the ast saved index.
3821 int literal_offset =
3822 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
3823 Result boilerplate = allocator_->Allocate();
3824 ASSERT(boilerplate.is_valid());
3825 __ mov(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset));
3826
3827 // Check whether we need to materialize the object literal boilerplate.
3828 // If so, jump to the deferred code passing the literals array.
3829 __ cmp(boilerplate.reg(), Factory::undefined_value());
3830 deferred->enter()->Branch(equal, &literals, not_taken);
3831
3832 literals.Unuse();
3833 // The deferred code returns the boilerplate object.
3834 deferred->BindExit(&boilerplate);
3835
3836 // Push the resulting array literal on the stack.
3837 frame_->Push(&boilerplate);
3838
3839 // Clone the boilerplate object.
3840 Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate;
3841 if (node->depth() == 1) {
3842 clone_function_id = Runtime::kCloneShallowLiteralBoilerplate;
3843 }
3844 Result clone = frame_->CallRuntime(clone_function_id, 1);
3845 // Push the newly cloned literal object as the result.
3846 frame_->Push(&clone);
3847
3848 // Generate code to set the elements in the array that are not
3849 // literals.
3850 for (int i = 0; i < node->values()->length(); i++) {
3851 Expression* value = node->values()->at(i);
3852
3853 // If value is a literal the property value is already set in the
3854 // boilerplate object.
3855 if (value->AsLiteral() != NULL) continue;
3856 // If value is a materialized literal the property value is already set
3857 // in the boilerplate object if it is simple.
3858 if (CompileTimeValue::IsCompileTimeValue(value)) continue;
3859
3860 // The property must be set by generated code.
3861 Load(value);
3862
3863 // Get the property value off the stack.
3864 Result prop_value = frame_->Pop();
3865 prop_value.ToRegister();
3866
3867 // Fetch the array literal while leaving a copy on the stack and
3868 // use it to get the elements array.
3869 frame_->Dup();
3870 Result elements = frame_->Pop();
3871 elements.ToRegister();
3872 frame_->Spill(elements.reg());
3873 // Get the elements array.
3874 __ mov(elements.reg(),
3875 FieldOperand(elements.reg(), JSObject::kElementsOffset));
3876
3877 // Write to the indexed properties array.
3878 int offset = i * kPointerSize + Array::kHeaderSize;
3879 __ mov(FieldOperand(elements.reg(), offset), prop_value.reg());
3880
3881 // Update the write barrier for the array address.
3882 frame_->Spill(prop_value.reg()); // Overwritten by the write barrier.
3883 Result scratch = allocator_->Allocate();
3884 ASSERT(scratch.is_valid());
3885 __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg());
3886 }
3887 }
3888
3889
3890 void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) {
3891 ASSERT(!in_spilled_code());
3892 // Call runtime routine to allocate the catch extension object and
3893 // assign the exception value to the catch variable.
3894 Comment cmnt(masm_, "[ CatchExtensionObject");
3895 Load(node->key());
3896 Load(node->value());
3897 Result result =
3898 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
3899 frame_->Push(&result);
3900 }
3901
3902
3903 void CodeGenerator::VisitAssignment(Assignment* node) {
3904 Comment cmnt(masm_, "[ Assignment");
3905 CodeForStatementPosition(node);
3906
3907 { Reference target(this, node->target());
3908 if (target.is_illegal()) {
3909 // Fool the virtual frame into thinking that we left the assignment's
3910 // value on the frame.
3911 frame_->Push(Smi::FromInt(0));
3912 return;
3913 }
3914 Variable* var = node->target()->AsVariableProxy()->AsVariable();
3915
3916 if (node->starts_initialization_block()) {
3917 ASSERT(target.type() == Reference::NAMED ||
3918 target.type() == Reference::KEYED);
3919 // Change to slow case in the beginning of an initialization
3920 // block to avoid the quadratic behavior of repeatedly adding
3921 // fast properties.
3922
3923 // The receiver is the argument to the runtime call. It is the
3924 // first value pushed when the reference was loaded to the
3925 // frame.
3926 frame_->PushElementAt(target.size() - 1);
3927 Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1);
3928 }
3929 if (node->op() == Token::ASSIGN ||
3930 node->op() == Token::INIT_VAR ||
3931 node->op() == Token::INIT_CONST) {
3932 Load(node->value());
3933
3934 } else {
3935 Literal* literal = node->value()->AsLiteral();
3936 bool overwrite_value =
3937 (node->value()->AsBinaryOperation() != NULL &&
3938 node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
3939 Variable* right_var = node->value()->AsVariableProxy()->AsVariable();
3940 // There are two cases where the target is not read in the right hand
3941 // side, that are easy to test for: the right hand side is a literal,
3942 // or the right hand side is a different variable. TakeValue invalidates
3943 // the target, with an implicit promise that it will be written to again
3944 // before it is read.
3945 if (literal != NULL || (right_var != NULL && right_var != var)) {
3946 target.TakeValue(NOT_INSIDE_TYPEOF);
3947 } else {
3948 target.GetValue(NOT_INSIDE_TYPEOF);
3949 }
3950 Load(node->value());
3951 GenericBinaryOperation(node->binary_op(),
3952 node->type(),
3953 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
3954 }
3955
3956 if (var != NULL &&
3957 var->mode() == Variable::CONST &&
3958 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
3959 // Assignment ignored - leave the value on the stack.
3960 } else {
3961 CodeForSourcePosition(node->position());
3962 if (node->op() == Token::INIT_CONST) {
3963 // Dynamic constant initializations must use the function context
3964 // and initialize the actual constant declared. Dynamic variable
3965 // initializations are simply assignments and use SetValue.
3966 target.SetValue(CONST_INIT);
3967 } else {
3968 target.SetValue(NOT_CONST_INIT);
3969 }
3970 if (node->ends_initialization_block()) {
3971 ASSERT(target.type() == Reference::NAMED ||
3972 target.type() == Reference::KEYED);
3973 // End of initialization block. Revert to fast case. The
3974 // argument to the runtime call is the receiver, which is the
3975 // first value pushed as part of the reference, which is below
3976 // the lhs value.
3977 frame_->PushElementAt(target.size());
3978 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1);
3979 }
3980 }
3981 }
3982 }
3983
3984
3985 void CodeGenerator::VisitThrow(Throw* node) {
3986 Comment cmnt(masm_, "[ Throw");
3987 CodeForStatementPosition(node);
3988
3989 Load(node->exception());
3990 Result result = frame_->CallRuntime(Runtime::kThrow, 1);
3991 frame_->Push(&result);
3992 }
3993
3994
3995 void CodeGenerator::VisitProperty(Property* node) {
3996 Comment cmnt(masm_, "[ Property");
3997 Reference property(this, node);
3998 property.GetValue(typeof_state());
3999 }
4000
4001
4002 void CodeGenerator::VisitCall(Call* node) {
4003 Comment cmnt(masm_, "[ Call");
4004
4005 ZoneList<Expression*>* args = node->arguments();
4006
4007 CodeForStatementPosition(node);
4008
4009 // Check if the function is a variable or a property.
4010 Expression* function = node->expression();
4011 Variable* var = function->AsVariableProxy()->AsVariable();
4012 Property* property = function->AsProperty();
4013
4014 // ------------------------------------------------------------------------
4015 // Fast-case: Use inline caching.
4016 // ---
4017 // According to ECMA-262, section 11.2.3, page 44, the function to call
4018 // must be resolved after the arguments have been evaluated. The IC code
4019 // automatically handles this by loading the arguments before the function
4020 // is resolved in cache misses (this also holds for megamorphic calls).
4021 // ------------------------------------------------------------------------
4022
4023 if (var != NULL && !var->is_this() && var->is_global()) {
4024 // ----------------------------------
4025 // JavaScript example: 'foo(1, 2, 3)' // foo is global
4026 // ----------------------------------
4027
4028 // Push the name of the function and the receiver onto the stack.
4029 frame_->Push(var->name());
4030
4031 // Pass the global object as the receiver and let the IC stub
4032 // patch the stack to use the global proxy as 'this' in the
4033 // invoked function.
4034 LoadGlobal();
4035
4036 // Load the arguments.
4037 int arg_count = args->length();
4038 for (int i = 0; i < arg_count; i++) {
4039 Load(args->at(i));
4040 }
4041
4042 // Call the IC initialization code.
4043 CodeForSourcePosition(node->position());
4044 Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT,
4045 arg_count,
4046 loop_nesting());
4047 frame_->RestoreContextRegister();
4048 // Replace the function on the stack with the result.
4049 frame_->SetElementAt(0, &result);
4050
4051 } else if (var != NULL && var->slot() != NULL &&
4052 var->slot()->type() == Slot::LOOKUP) {
4053 // ----------------------------------
4054 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj
4055 // ----------------------------------
4056
4057 // Load the function
4058 frame_->Push(esi);
4059 frame_->Push(var->name());
4060 frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
4061 // eax: slot value; edx: receiver
4062
4063 // Load the receiver.
4064 frame_->Push(eax);
4065 frame_->Push(edx);
4066
4067 // Call the function.
4068 CallWithArguments(args, node->position());
4069
4070 } else if (property != NULL) {
4071 // Check if the key is a literal string.
4072 Literal* literal = property->key()->AsLiteral();
4073
4074 if (literal != NULL && literal->handle()->IsSymbol()) {
4075 // ------------------------------------------------------------------
4076 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
4077 // ------------------------------------------------------------------
4078
4079 // Push the name of the function and the receiver onto the stack.
4080 frame_->Push(literal->handle());
4081 Load(property->obj());
4082
4083 // Load the arguments.
4084 int arg_count = args->length();
4085 for (int i = 0; i < arg_count; i++) {
4086 Load(args->at(i));
4087 }
4088
4089 // Call the IC initialization code.
4090 CodeForSourcePosition(node->position());
4091 Result result =
4092 frame_->CallCallIC(RelocInfo::CODE_TARGET, arg_count, loop_nesting());
4093 frame_->RestoreContextRegister();
4094 // Replace the function on the stack with the result.
4095 frame_->SetElementAt(0, &result);
4096
4097 } else {
4098 // -------------------------------------------
4099 // JavaScript example: 'array[index](1, 2, 3)'
4100 // -------------------------------------------
4101
4102 // Load the function to call from the property through a reference.
4103 Reference ref(this, property);
4104 ref.GetValue(NOT_INSIDE_TYPEOF);
4105
4106 // Pass receiver to called function.
4107 if (property->is_synthetic()) {
4108 // Use global object as receiver.
4109 LoadGlobalReceiver();
4110 } else {
4111 // The reference's size is non-negative.
4112 frame_->PushElementAt(ref.size());
4113 }
4114
4115 // Call the function.
4116 CallWithArguments(args, node->position());
4117 }
4118
4119 } else {
4120 // ----------------------------------
4121 // JavaScript example: 'foo(1, 2, 3)' // foo is not global
4122 // ----------------------------------
4123
4124 // Load the function.
4125 Load(function);
4126
4127 // Pass the global proxy as the receiver.
4128 LoadGlobalReceiver();
4129
4130 // Call the function.
4131 CallWithArguments(args, node->position());
4132 }
4133 }
4134
4135
4136 void CodeGenerator::VisitCallNew(CallNew* node) {
4137 Comment cmnt(masm_, "[ CallNew");
4138 CodeForStatementPosition(node);
4139
4140 // According to ECMA-262, section 11.2.2, page 44, the function
4141 // expression in new calls must be evaluated before the
4142 // arguments. This is different from ordinary calls, where the
4143 // actual function to call is resolved after the arguments have been
4144 // evaluated.
4145
4146 // Compute function to call and use the global object as the
4147 // receiver. There is no need to use the global proxy here because
4148 // it will always be replaced with a newly allocated object.
4149 Load(node->expression());
4150 LoadGlobal();
4151
4152 // Push the arguments ("left-to-right") on the stack.
4153 ZoneList<Expression*>* args = node->arguments();
4154 int arg_count = args->length();
4155 for (int i = 0; i < arg_count; i++) {
4156 Load(args->at(i));
4157 }
4158
4159 // Call the construct call builtin that handles allocation and
4160 // constructor invocation.
4161 CodeForSourcePosition(node->position());
4162 Result result = frame_->CallConstructor(arg_count);
4163 // Replace the function on the stack with the result.
4164 frame_->SetElementAt(0, &result);
4165 }
4166
4167
4168 void CodeGenerator::VisitCallEval(CallEval* node) {
4169 Comment cmnt(masm_, "[ CallEval");
4170
4171 // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve
4172 // the function we need to call and the receiver of the call.
4173 // Then we call the resolved function using the given arguments.
4174
4175 ZoneList<Expression*>* args = node->arguments();
4176 Expression* function = node->expression();
4177
4178 CodeForStatementPosition(node);
4179
4180 // Prepare the stack for the call to the resolved function.
4181 Load(function);
4182
4183 // Allocate a frame slot for the receiver.
4184 frame_->Push(Factory::undefined_value());
4185 int arg_count = args->length();
4186 for (int i = 0; i < arg_count; i++) {
4187 Load(args->at(i));
4188 }
4189
4190 // Prepare the stack for the call to ResolvePossiblyDirectEval.
4191 frame_->PushElementAt(arg_count + 1);
4192 if (arg_count > 0) {
4193 frame_->PushElementAt(arg_count);
4194 } else {
4195 frame_->Push(Factory::undefined_value());
4196 }
4197
4198 // Resolve the call.
4199 Result result =
4200 frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
4201
4202 // Touch up the stack with the right values for the function and the
4203 // receiver. Use a scratch register to avoid destroying the result.
4204 Result scratch = allocator_->Allocate();
4205 ASSERT(scratch.is_valid());
4206 __ mov(scratch.reg(), FieldOperand(result.reg(), FixedArray::kHeaderSize));
4207 frame_->SetElementAt(arg_count + 1, &scratch);
4208
4209 // We can reuse the result register now.
4210 frame_->Spill(result.reg());
4211 __ mov(result.reg(),
4212 FieldOperand(result.reg(), FixedArray::kHeaderSize + kPointerSize));
4213 frame_->SetElementAt(arg_count, &result);
4214
4215 // Call the function.
4216 CodeForSourcePosition(node->position());
4217 CallFunctionStub call_function(arg_count);
4218 result = frame_->CallStub(&call_function, arg_count + 1);
4219
4220 // Restore the context and overwrite the function on the stack with
4221 // the result.
4222 frame_->RestoreContextRegister();
4223 frame_->SetElementAt(0, &result);
4224 }
4225
4226
4227 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
4228 ASSERT(args->length() == 1);
4229 Load(args->at(0));
4230 Result value = frame_->Pop();
4231 value.ToRegister();
4232 ASSERT(value.is_valid());
4233 __ test(value.reg(), Immediate(kSmiTagMask));
4234 value.Unuse();
4235 destination()->Split(zero);
4236 }
4237
4238
4239 void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) {
4240 // Conditionally generate a log call.
4241 // Args:
4242 // 0 (literal string): The type of logging (corresponds to the flags).
4243 // This is used to determine whether or not to generate the log call.
4244 // 1 (string): Format string. Access the string at argument index 2
4245 // with '%2s' (see Logger::LogRuntime for all the formats).
4246 // 2 (array): Arguments to the format string.
4247 ASSERT_EQ(args->length(), 3);
4248 #ifdef ENABLE_LOGGING_AND_PROFILING
4249 if (ShouldGenerateLog(args->at(0))) {
4250 Load(args->at(1));
4251 Load(args->at(2));
4252 frame_->CallRuntime(Runtime::kLog, 2);
4253 }
4254 #endif
4255 // Finally, we're expected to leave a value on the top of the stack.
4256 frame_->Push(Factory::undefined_value());
4257 }
4258
4259
4260 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
4261 ASSERT(args->length() == 1);
4262 Load(args->at(0));
4263 Result value = frame_->Pop();
4264 value.ToRegister();
4265 ASSERT(value.is_valid());
4266 __ test(value.reg(), Immediate(kSmiTagMask | 0x80000000));
4267 value.Unuse();
4268 destination()->Split(zero);
4269 }
4270
4271
4272 // This generates code that performs a charCodeAt() call or returns
4273 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
4274 // It can handle flat and sliced strings, 8 and 16 bit characters and
4275 // cons strings where the answer is found in the left hand branch of the
4276 // cons. The slow case will flatten the string, which will ensure that
4277 // the answer is in the left hand side the next time around.
4278 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
4279 ASSERT(args->length() == 2);
4280
4281 JumpTarget slow_case(this);
4282 JumpTarget end(this);
4283 JumpTarget not_a_flat_string(this);
4284 JumpTarget a_cons_string(this);
4285 JumpTarget try_again_with_new_string(this, JumpTarget::BIDIRECTIONAL);
4286 JumpTarget ascii_string(this);
4287 JumpTarget got_char_code(this);
4288
4289 Load(args->at(0));
4290 Load(args->at(1));
4291 // Reserve register ecx, to use as shift amount later
4292 Result shift_amount = allocator()->Allocate(ecx);
4293 ASSERT(shift_amount.is_valid());
4294 Result index = frame_->Pop();
4295 index.ToRegister();
4296 Result object = frame_->Pop();
4297 object.ToRegister();
4298 // If the receiver is a smi return undefined.
4299 ASSERT(kSmiTag == 0);
4300 __ test(object.reg(), Immediate(kSmiTagMask));
4301 slow_case.Branch(zero, not_taken);
4302
4303 // Check for negative or non-smi index.
4304 ASSERT(kSmiTag == 0);
4305 __ test(index.reg(), Immediate(kSmiTagMask | 0x80000000));
4306 slow_case.Branch(not_zero, not_taken);
4307 // Get rid of the smi tag on the index.
4308 frame_->Spill(index.reg());
4309 __ sar(index.reg(), kSmiTagSize);
4310
4311 try_again_with_new_string.Bind(&object, &index, &shift_amount);
4312 // Get the type of the heap object.
4313 Result object_type = allocator()->Allocate();
4314 ASSERT(object_type.is_valid());
4315 __ mov(object_type.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset));
4316 __ movzx_b(object_type.reg(),
4317 FieldOperand(object_type.reg(), Map::kInstanceTypeOffset));
4318 // We don't handle non-strings.
4319 __ test(object_type.reg(), Immediate(kIsNotStringMask));
4320 slow_case.Branch(not_zero, not_taken);
4321
4322 // Here we make assumptions about the tag values and the shifts needed.
4323 // See the comment in objects.h.
4324 ASSERT(kLongStringTag == 0);
4325 ASSERT(kMediumStringTag + String::kLongLengthShift ==
4326 String::kMediumLengthShift);
4327 ASSERT(kShortStringTag + String::kLongLengthShift ==
4328 String::kShortLengthShift);
4329 __ mov(shift_amount.reg(), Operand(object_type.reg()));
4330 __ and_(shift_amount.reg(), kStringSizeMask);
4331 __ add(Operand(shift_amount.reg()), Immediate(String::kLongLengthShift));
4332 // Get the length field. Temporary register now used for length.
4333 Result length = object_type;
4334 __ mov(length.reg(), FieldOperand(object.reg(), String::kLengthOffset));
4335 __ shr(length.reg()); // shift_amount, in ecx, is implicit operand.
4336 // Check for index out of range.
4337 __ cmp(index.reg(), Operand(length.reg()));
4338 slow_case.Branch(greater_equal, not_taken);
4339 length.Unuse();
4340 // Load the object type into object_type again.
4341 // These two instructions are duplicated from above, to save a register.
4342 __ mov(object_type.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset));
4343 __ movzx_b(object_type.reg(),
4344 FieldOperand(object_type.reg(), Map::kInstanceTypeOffset));
4345
4346 // We need special handling for non-flat strings.
4347 ASSERT(kSeqStringTag == 0);
4348 __ test(object_type.reg(), Immediate(kStringRepresentationMask));
4349 not_a_flat_string.Branch(not_zero, &object, &index, &object_type,
4350 &shift_amount, not_taken);
4351 shift_amount.Unuse();
4352 // Check for 1-byte or 2-byte string.
4353 __ test(object_type.reg(), Immediate(kStringEncodingMask));
4354 ascii_string.Branch(not_zero, &object, &index, &object_type, taken);
4355
4356 // 2-byte string.
4357 // Load the 2-byte character code.
4358 __ movzx_w(object_type.reg(), FieldOperand(object.reg(),
4359 index.reg(),
4360 times_2,
4361 SeqTwoByteString::kHeaderSize));
4362 object.Unuse();
4363 index.Unuse();
4364 got_char_code.Jump(&object_type);
4365
4366 // ASCII string.
4367 ascii_string.Bind(&object, &index, &object_type);
4368 // Load the byte.
4369 __ movzx_b(object_type.reg(), FieldOperand(object.reg(),
4370 index.reg(),
4371 times_1,
4372 SeqAsciiString::kHeaderSize));
4373 object.Unuse();
4374 index.Unuse();
4375 got_char_code.Bind(&object_type);
4376 ASSERT(kSmiTag == 0);
4377 __ shl(object_type.reg(), kSmiTagSize);
4378 frame_->Push(&object_type);
4379 end.Jump();
4380
4381 // Handle non-flat strings.
4382 not_a_flat_string.Bind(&object, &index, &object_type, &shift_amount);
4383 __ and_(object_type.reg(), kStringRepresentationMask);
4384 __ cmp(object_type.reg(), kConsStringTag);
4385 a_cons_string.Branch(equal, &object, &index, &shift_amount, taken);
4386 __ cmp(object_type.reg(), kSlicedStringTag);
4387 slow_case.Branch(not_equal, not_taken);
4388 object_type.Unuse();
4389
4390 // SlicedString.
4391 // Add the offset to the index.
4392 __ add(index.reg(), FieldOperand(object.reg(), SlicedString::kStartOffset));
4393 slow_case.Branch(overflow);
4394 // Getting the underlying string is done by running the cons string code.
4395
4396 // ConsString.
4397 a_cons_string.Bind(&object, &index, &shift_amount);
4398 // Get the first of the two strings.
4399 frame_->Spill(object.reg());
4400 // Both sliced and cons strings store their source string at the same place.
4401 ASSERT(SlicedString::kBufferOffset == ConsString::kFirstOffset);
4402 __ mov(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset));
4403 try_again_with_new_string.Jump(&object, &index, &shift_amount);
4404
4405 // No results live at this point.
4406 slow_case.Bind();
4407 frame_->Push(Factory::undefined_value());
4408 end.Bind();
4409 }
4410
4411
4412 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
4413 ASSERT(args->length() == 1);
4414 Load(args->at(0));
4415 Result value = frame_->Pop();
4416 value.ToRegister();
4417 ASSERT(value.is_valid());
4418 __ test(value.reg(), Immediate(kSmiTagMask));
4419 destination()->false_target()->Branch(equal);
4420 // It is a heap object - get map.
4421 Result temp = allocator()->Allocate();
4422 ASSERT(temp.is_valid());
4423 // Check if the object is a JS array or not.
4424 __ CmpObjectType(value.reg(), JS_ARRAY_TYPE, temp.reg());
4425 value.Unuse();
4426 temp.Unuse();
4427 destination()->Split(equal);
4428 }
4429
4430
4431 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
4432 ASSERT(args->length() == 0);
4433 // ArgumentsAccessStub takes the parameter count as an input argument
4434 // in register eax. Create a constant result for it.
4435 Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters())), this);
4436 // Call the shared stub to get to the arguments.length.
4437 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
4438 Result result = frame_->CallStub(&stub, &count);
4439 frame_->Push(&result);
4440 }
4441
4442
4443 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
4444 ASSERT(args->length() == 1);
4445 JumpTarget leave(this);
4446 Load(args->at(0)); // Load the object.
4447 frame_->Dup();
4448 Result object = frame_->Pop();
4449 object.ToRegister();
4450 ASSERT(object.is_valid());
4451 // if (object->IsSmi()) return object.
4452 __ test(object.reg(), Immediate(kSmiTagMask));
4453 leave.Branch(zero, taken);
4454 // It is a heap object - get map.
4455 Result temp = allocator()->Allocate();
4456 ASSERT(temp.is_valid());
4457 // if (!object->IsJSValue()) return object.
4458 __ CmpObjectType(object.reg(), JS_VALUE_TYPE, temp.reg());
4459 leave.Branch(not_equal, not_taken);
4460 __ mov(temp.reg(), FieldOperand(object.reg(), JSValue::kValueOffset));
4461 object.Unuse();
4462 frame_->SetElementAt(0, &temp);
4463 leave.Bind();
4464 }
4465
4466
4467 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
4468 ASSERT(args->length() == 2);
4469 JumpTarget leave(this);
4470 Load(args->at(0)); // Load the object.
4471 Load(args->at(1)); // Load the value.
4472 Result value = frame_->Pop();
4473 Result object = frame_->Pop();
4474 value.ToRegister();
4475 object.ToRegister();
4476
4477 // if (object->IsSmi()) return value.
4478 __ test(object.reg(), Immediate(kSmiTagMask));
4479 leave.Branch(zero, &value, taken);
4480
4481 // It is a heap object - get its map.
4482 Result scratch = allocator_->Allocate();
4483 ASSERT(scratch.is_valid());
4484 // if (!object->IsJSValue()) return value.
4485 __ CmpObjectType(object.reg(), JS_VALUE_TYPE, scratch.reg());
4486 leave.Branch(not_equal, &value, not_taken);
4487
4488 // Store the value.
4489 __ mov(FieldOperand(object.reg(), JSValue::kValueOffset), value.reg());
4490 // Update the write barrier. Save the value as it will be
4491 // overwritten by the write barrier code and is needed afterward.
4492 Result duplicate_value = allocator_->Allocate();
4493 ASSERT(duplicate_value.is_valid());
4494 __ mov(duplicate_value.reg(), value.reg());
4495 // The object register is also overwritten by the write barrier and
4496 // possibly aliased in the frame.
4497 frame_->Spill(object.reg());
4498 __ RecordWrite(object.reg(), JSValue::kValueOffset, duplicate_value.reg(),
4499 scratch.reg());
4500 object.Unuse();
4501 scratch.Unuse();
4502 duplicate_value.Unuse();
4503
4504 // Leave.
4505 leave.Bind(&value);
4506 frame_->Push(&value);
4507 }
4508
4509
4510 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
4511 ASSERT(args->length() == 1);
4512
4513 // ArgumentsAccessStub expects the key in edx and the formal
4514 // parameter count in eax.
4515 Load(args->at(0));
4516 Result key = frame_->Pop();
4517 // Explicitly create a constant result.
4518 Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters())), this);
4519 // Call the shared stub to get to arguments[key].
4520 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
4521 Result result = frame_->CallStub(&stub, &key, &count);
4522 frame_->Push(&result);
4523 }
4524
4525
4526 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
4527 ASSERT(args->length() == 2);
4528
4529 // Load the two objects into registers and perform the comparison.
4530 Load(args->at(0));
4531 Load(args->at(1));
4532 Result right = frame_->Pop();
4533 Result left = frame_->Pop();
4534 right.ToRegister();
4535 left.ToRegister();
4536 __ cmp(right.reg(), Operand(left.reg()));
4537 right.Unuse();
4538 left.Unuse();
4539 destination()->Split(equal);
4540 }
4541
4542
4543 void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
4544 if (CheckForInlineRuntimeCall(node)) {
4545 return;
4546 }
4547
4548 ZoneList<Expression*>* args = node->arguments();
4549 Comment cmnt(masm_, "[ CallRuntime");
4550 Runtime::Function* function = node->function();
4551
4552 if (function == NULL) {
4553 // Prepare stack for calling JS runtime function.
4554 frame_->Push(node->name());
4555 // Push the builtins object found in the current global object.
4556 Result temp = allocator()->Allocate();
4557 ASSERT(temp.is_valid());
4558 __ mov(temp.reg(), GlobalObject());
4559 __ mov(temp.reg(), FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset));
4560 frame_->Push(&temp);
4561 }
4562
4563 // Push the arguments ("left-to-right").
4564 int arg_count = args->length();
4565 for (int i = 0; i < arg_count; i++) {
4566 Load(args->at(i));
4567 }
4568
4569 if (function == NULL) {
4570 // Call the JS runtime function. Pass 0 as the loop nesting depth
4571 // because we do not handle runtime calls specially in loops.
4572 Result answer = frame_->CallCallIC(RelocInfo::CODE_TARGET, arg_count, 0);
4573 frame_->RestoreContextRegister();
4574 frame_->SetElementAt(0, &answer);
4575 } else {
4576 // Call the C runtime function.
4577 Result answer = frame_->CallRuntime(function, arg_count);
4578 frame_->Push(&answer);
4579 }
4580 }
4581
4582
4583 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
4584 // Note that because of NOT and an optimization in comparison of a typeof
4585 // expression to a literal string, this function can fail to leave a value
4586 // on top of the frame or in the cc register.
4587 Comment cmnt(masm_, "[ UnaryOperation");
4588
4589 Token::Value op = node->op();
4590
4591 if (op == Token::NOT) {
4592 // Swap the true and false targets but keep the same actual label
4593 // as the fall through.
4594 destination()->Invert();
4595 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, destination(), true);
4596 // Swap the labels back.
4597 destination()->Invert();
4598
4599 } else if (op == Token::DELETE) {
4600 Property* property = node->expression()->AsProperty();
4601 if (property != NULL) {
4602 Load(property->obj());
4603 Load(property->key());
4604 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2);
4605 frame_->Push(&answer);
4606 return;
4607 }
4608
4609 Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
4610 if (variable != NULL) {
4611 Slot* slot = variable->slot();
4612 if (variable->is_global()) {
4613 LoadGlobal();
4614 frame_->Push(variable->name());
4615 Result answer = frame_->InvokeBuiltin(Builtins::DELETE,
4616 CALL_FUNCTION, 2);
4617 frame_->Push(&answer);
4618 return;
4619
4620 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
4621 // lookup the context holding the named variable
4622 frame_->Push(esi);
4623 frame_->Push(variable->name());
4624 Result context = frame_->CallRuntime(Runtime::kLookupContext, 2);
4625 frame_->Push(&context);
4626 frame_->Push(variable->name());
4627 Result answer = frame_->InvokeBuiltin(Builtins::DELETE,
4628 CALL_FUNCTION, 2);
4629 frame_->Push(&answer);
4630 return;
4631 }
4632
4633 // Default: Result of deleting non-global, not dynamically
4634 // introduced variables is false.
4635 frame_->Push(Factory::false_value());
4636
4637 } else {
4638 // Default: Result of deleting expressions is true.
4639 Load(node->expression()); // may have side-effects
4640 frame_->SetElementAt(0, Factory::true_value());
4641 }
4642
4643 } else if (op == Token::TYPEOF) {
4644 // Special case for loading the typeof expression; see comment on
4645 // LoadTypeofExpression().
4646 LoadTypeofExpression(node->expression());
4647 Result answer = frame_->CallRuntime(Runtime::kTypeof, 1);
4648 frame_->Push(&answer);
4649
4650 } else if (op == Token::VOID) {
4651 Expression* expression = node->expression();
4652 if (expression && expression->AsLiteral() && (
4653 expression->AsLiteral()->IsTrue() ||
4654 expression->AsLiteral()->IsFalse() ||
4655 expression->AsLiteral()->handle()->IsNumber() ||
4656 expression->AsLiteral()->handle()->IsString() ||
4657 expression->AsLiteral()->handle()->IsJSRegExp() ||
4658 expression->AsLiteral()->IsNull())) {
4659 // Omit evaluating the value of the primitive literal.
4660 // It will be discarded anyway, and can have no side effect.
4661 frame_->Push(Factory::undefined_value());
4662 } else {
4663 Load(node->expression());
4664 frame_->SetElementAt(0, Factory::undefined_value());
4665 }
4666
4667 } else {
4668 Load(node->expression());
4669 switch (op) {
4670 case Token::NOT:
4671 case Token::DELETE:
4672 case Token::TYPEOF:
4673 UNREACHABLE(); // handled above
4674 break;
4675
4676 case Token::SUB: {
4677 UnarySubStub stub;
4678 // TODO(1222589): remove dependency of TOS being cached inside stub
4679 Result operand = frame_->Pop();
4680 Result answer = frame_->CallStub(&stub, &operand);
4681 frame_->Push(&answer);
4682 break;
4683 }
4684
4685 case Token::BIT_NOT: {
4686 // Smi check.
4687 JumpTarget smi_label(this);
4688 JumpTarget continue_label(this);
4689 Result operand = frame_->Pop();
4690 operand.ToRegister();
4691 __ test(operand.reg(), Immediate(kSmiTagMask));
4692 smi_label.Branch(zero, &operand, taken);
4693
4694 frame_->Push(&operand); // undo popping of TOS
4695 Result answer = frame_->InvokeBuiltin(Builtins::BIT_NOT,
4696 CALL_FUNCTION, 1);
4697
4698 continue_label.Jump(&answer);
4699 smi_label.Bind(&answer);
4700 answer.ToRegister();
4701 frame_->Spill(answer.reg());
4702 __ not_(answer.reg());
4703 __ and_(answer.reg(), ~kSmiTagMask); // Remove inverted smi-tag.
4704 continue_label.Bind(&answer);
4705 frame_->Push(&answer);
4706 break;
4707 }
4708
4709 case Token::ADD: {
4710 // Smi check.
4711 JumpTarget continue_label(this);
4712 Result operand = frame_->Pop();
4713 operand.ToRegister();
4714 __ test(operand.reg(), Immediate(kSmiTagMask));
4715 continue_label.Branch(zero, &operand, taken);
4716
4717 frame_->Push(&operand);
4718 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER,
4719 CALL_FUNCTION, 1);
4720
4721 continue_label.Bind(&answer);
4722 frame_->Push(&answer);
4723 break;
4724 }
4725
4726 default:
4727 UNREACHABLE();
4728 }
4729 }
4730 }
4731
4732
4733 class DeferredCountOperation: public DeferredCode {
4734 public:
4735 DeferredCountOperation(CodeGenerator* generator,
4736 bool is_postfix,
4737 bool is_increment,
4738 int target_size)
4739 : DeferredCode(generator),
4740 is_postfix_(is_postfix),
4741 is_increment_(is_increment),
4742 target_size_(target_size) {
4743 set_comment("[ DeferredCountOperation");
4744 }
4745
4746 virtual void Generate();
4747
4748 private:
4749 bool is_postfix_;
4750 bool is_increment_;
4751 int target_size_;
4752 };
4753
4754
4755 void DeferredCountOperation::Generate() {
4756 CodeGenerator* cgen = generator();
4757 Result value(cgen);
4758 enter()->Bind(&value);
4759 VirtualFrame* frame = cgen->frame();
4760 // Undo the optimistic smi operation.
4761 value.ToRegister();
4762 frame->Spill(value.reg());
4763 if (is_increment_) {
4764 __ sub(Operand(value.reg()), Immediate(Smi::FromInt(1)));
4765 } else {
4766 __ add(Operand(value.reg()), Immediate(Smi::FromInt(1)));
4767 }
4768 frame->Push(&value);
4769 value = frame->InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION, 1);
4770 frame->Push(&value);
4771 if (is_postfix_) { // Fix up copy of old value with ToNumber(value).
4772 // This is only safe because VisitCountOperation makes this frame slot
4773 // beneath the reference a register, which is spilled at the above call.
4774 // We cannot safely write to constants or copies below the water line.
4775 frame->StoreToElementAt(target_size_ + 1);
4776 }
4777 frame->Push(Smi::FromInt(1));
4778 if (is_increment_) {
4779 value = frame->CallRuntime(Runtime::kNumberAdd, 2);
4780 } else {
4781 value = frame->CallRuntime(Runtime::kNumberSub, 2);
4782 }
4783 exit_.Jump(&value);
4784 }
4785
4786
4787 void CodeGenerator::VisitCountOperation(CountOperation* node) {
4788 Comment cmnt(masm_, "[ CountOperation");
4789
4790 bool is_postfix = node->is_postfix();
4791 bool is_increment = node->op() == Token::INC;
4792
4793 Variable* var = node->expression()->AsVariableProxy()->AsVariable();
4794 bool is_const = (var != NULL && var->mode() == Variable::CONST);
4795
4796 // Postfix operators need a stack slot under the reference to hold
4797 // the old value while the new one is being stored.
4798 if (is_postfix) {
4799 frame_->Push(Smi::FromInt(0));
4800 }
4801
4802 { Reference target(this, node->expression());
4803 if (target.is_illegal()) {
4804 // Spoof the virtual frame to have the expected height (one higher
4805 // than on entry).
4806 if (!is_postfix) {
4807 frame_->Push(Smi::FromInt(0));
4808 }
4809 return;
4810 }
4811 target.TakeValue(NOT_INSIDE_TYPEOF);
4812
4813 DeferredCountOperation* deferred =
4814 new DeferredCountOperation(this, is_postfix,
4815 is_increment, target.size());
4816
4817 Result value = frame_->Pop();
4818 value.ToRegister();
4819
4820 // Postfix: Store the old value as the result.
4821 if (is_postfix) {
4822 // Explicitly back the slot for the old value with a new register.
4823 // This improves performance in some cases.
4824 Result old_value = allocator_->Allocate();
4825 ASSERT(old_value.is_valid());
4826 __ mov(old_value.reg(), value.reg());
4827 // SetElement must not create a constant element or a copy in this slot,
4828 // since we will write to it, below the waterline, in deferred code.
4829 frame_->SetElementAt(target.size(), &old_value);
4830 }
4831
4832 // Perform optimistic increment/decrement. Ensure the value is
4833 // writable.
4834 frame_->Spill(value.reg());
4835 ASSERT(allocator_->count(value.reg()) == 1);
4836
4837 // In order to combine the overflow and the smi check, we need to
4838 // be able to allocate a byte register. We attempt to do so
4839 // without spilling. If we fail, we will generate separate
4840 // overflow and smi checks.
4841 //
4842 // We need to allocate and clear the temporary byte register
4843 // before performing the count operation since clearing the
4844 // register using xor will clear the overflow flag.
4845 Result tmp = allocator_->AllocateByteRegisterWithoutSpilling();
4846 if (tmp.is_valid()) {
4847 __ Set(tmp.reg(), Immediate(0));
4848 }
4849
4850 if (is_increment) {
4851 __ add(Operand(value.reg()), Immediate(Smi::FromInt(1)));
4852 } else {
4853 __ sub(Operand(value.reg()), Immediate(Smi::FromInt(1)));
4854 }
4855
4856 // If the count operation didn't overflow and the result is a
4857 // valid smi, we're done. Otherwise, we jump to the deferred
4858 // slow-case code.
4859 //
4860 // We combine the overflow and the smi check if we could
4861 // successfully allocate a temporary byte register.
4862 if (tmp.is_valid()) {
4863 __ setcc(overflow, tmp.reg());
4864 __ or_(Operand(value.reg()), tmp.reg());
4865 tmp.Unuse();
4866 __ test(value.reg(), Immediate(kSmiTagMask));
4867 deferred->enter()->Branch(not_zero, &value, not_taken);
4868 } else { // Otherwise we test separately for overflow and smi check.
4869 deferred->enter()->Branch(overflow, &value, not_taken);
4870 __ test(value.reg(), Immediate(kSmiTagMask));
4871 deferred->enter()->Branch(not_zero, &value, not_taken);
4872 }
4873
4874 // Store the new value in the target if not const.
4875 deferred->BindExit(&value);
4876 frame_->Push(&value);
4877 if (!is_const) {
4878 target.SetValue(NOT_CONST_INIT);
4879 }
4880 }
4881
4882 // Postfix: Discard the new value and use the old.
4883 if (is_postfix) {
4884 frame_->Drop();
4885 }
4886 }
4887
4888
4889 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
4890 // Note that due to an optimization in comparison operations (typeof
4891 // compared to a string literal), we can evaluate a binary expression such
4892 // as AND or OR and not leave a value on the frame or in the cc register.
4893 Comment cmnt(masm_, "[ BinaryOperation");
4894 Token::Value op = node->op();
4895
4896 // According to ECMA-262 section 11.11, page 58, the binary logical
4897 // operators must yield the result of one of the two expressions
4898 // before any ToBoolean() conversions. This means that the value
4899 // produced by a && or || operator is not necessarily a boolean.
4900
4901 // NOTE: If the left hand side produces a materialized value (not
4902 // control flow), we force the right hand side to do the same. This
4903 // is necessary because we assume that if we get control flow on the
4904 // last path out of an expression we got it on all paths.
4905 if (op == Token::AND) {
4906 JumpTarget is_true(this);
4907 ControlDestination dest(&is_true, destination()->false_target(), true);
4908 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false);
4909
4910 if (dest.false_was_fall_through()) {
4911 // The current false target was used as the fall-through. If
4912 // there are no dangling jumps to is_true then the left
4913 // subexpression was unconditionally false. Otherwise we have
4914 // paths where we do have to evaluate the right subexpression.
4915 if (is_true.is_linked()) {
4916 // We need to compile the right subexpression. If the jump to
4917 // the current false target was a forward jump then we have a
4918 // valid frame, we have just bound the false target, and we
4919 // have to jump around the code for the right subexpression.
4920 if (has_valid_frame()) {
4921 destination()->false_target()->Unuse();
4922 destination()->false_target()->Jump();
4923 }
4924 is_true.Bind();
4925 // The left subexpression compiled to control flow, so the
4926 // right one is free to do so as well.
4927 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false);
4928 } else {
4929 // We have actually just jumped to or bound the current false
4930 // target but the current control destination is not marked as
4931 // used.
4932 destination()->Use(false);
4933 }
4934
4935 } else if (dest.is_used()) {
4936 // The left subexpression compiled to control flow (and is_true
4937 // was just bound), so the right is free to do so as well.
4938 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false);
4939
4940 } else {
4941 // We have a materialized value on the frame, so we exit with
4942 // one on all paths. There are possibly also jumps to is_true
4943 // from nested subexpressions.
4944 JumpTarget pop_and_continue(this);
4945 JumpTarget exit(this);
4946
4947 // Avoid popping the result if it converts to 'false' using the
4948 // standard ToBoolean() conversion as described in ECMA-262,
4949 // section 9.2, page 30.
4950 //
4951 // Duplicate the TOS value. The duplicate will be popped by
4952 // ToBoolean.
4953 frame_->Dup();
4954 ControlDestination dest(&pop_and_continue, &exit, true);
4955 ToBoolean(&dest);
4956
4957 // Pop the result of evaluating the first part.
4958 frame_->Drop();
4959
4960 // Compile right side expression.
4961 is_true.Bind();
4962 Load(node->right());
4963
4964 // Exit (always with a materialized value).
4965 exit.Bind();
4966 }
4967
4968 } else if (op == Token::OR) {
4969 JumpTarget is_false(this);
4970 ControlDestination dest(destination()->true_target(), &is_false, false);
4971 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false);
4972
4973 if (dest.true_was_fall_through()) {
4974 // The current true target was used as the fall-through. If
4975 // there are no dangling jumps to is_false then the left
4976 // subexpression was unconditionally true. Otherwise we have
4977 // paths where we do have to evaluate the right subexpression.
4978 if (is_false.is_linked()) {
4979 // We need to compile the right subexpression. If the jump to
4980 // the current true target was a forward jump then we have a
4981 // valid frame, we have just bound the true target, and we
4982 // have to jump around the code for the right subexpression.
4983 if (has_valid_frame()) {
4984 destination()->true_target()->Unuse();
4985 destination()->true_target()->Jump();
4986 }
4987 is_false.Bind();
4988 // The left subexpression compiled to control flow, so the
4989 // right one is free to do so as well.
4990 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false);
4991 } else {
4992 // We have just jumped to or bound the current true target but
4993 // the current control destination is not marked as used.
4994 destination()->Use(true);
4995 }
4996
4997 } else if (dest.is_used()) {
4998 // The left subexpression compiled to control flow (and is_false
4999 // was just bound), so the right is free to do so as well.
5000 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false);
5001
5002 } else {
5003 // We have a materialized value on the frame, so we exit with
5004 // one on all paths. There are possibly also jumps to is_false
5005 // from nested subexpressions.
5006 JumpTarget pop_and_continue(this);
5007 JumpTarget exit(this);
5008
5009 // Avoid popping the result if it converts to 'true' using the
5010 // standard ToBoolean() conversion as described in ECMA-262,
5011 // section 9.2, page 30.
5012 //
5013 // Duplicate the TOS value. The duplicate will be popped by
5014 // ToBoolean.
5015 frame_->Dup();
5016 ControlDestination dest(&exit, &pop_and_continue, false);
5017 ToBoolean(&dest);
5018
5019 // Pop the result of evaluating the first part.
5020 frame_->Drop();
5021
5022 // Compile right side expression.
5023 is_false.Bind();
5024 Load(node->right());
5025
5026 // Exit (always with a materialized value).
5027 exit.Bind();
5028 }
5029
5030 } else {
5031 // NOTE: The code below assumes that the slow cases (calls to runtime)
5032 // never return a constant/immutable object.
5033 OverwriteMode overwrite_mode = NO_OVERWRITE;
5034 if (node->left()->AsBinaryOperation() != NULL &&
5035 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) {
5036 overwrite_mode = OVERWRITE_LEFT;
5037 } else if (node->right()->AsBinaryOperation() != NULL &&
5038 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) {
5039 overwrite_mode = OVERWRITE_RIGHT;
5040 }
5041
5042 Load(node->left());
5043 Load(node->right());
5044 GenericBinaryOperation(node->op(), node->type(), overwrite_mode);
5045 }
5046 }
5047
5048
5049 void CodeGenerator::VisitThisFunction(ThisFunction* node) {
5050 frame_->PushFunction();
5051 }
5052
5053
5054 class InstanceofStub: public CodeStub {
5055 public:
5056 InstanceofStub() { }
5057
5058 void Generate(MacroAssembler* masm);
5059
5060 private:
5061 Major MajorKey() { return Instanceof; }
5062 int MinorKey() { return 0; }
5063 };
5064
5065
5066 void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
5067 Comment cmnt(masm_, "[ CompareOperation");
5068
5069 // Get the expressions from the node.
5070 Expression* left = node->left();
5071 Expression* right = node->right();
5072 Token::Value op = node->op();
5073 // To make typeof testing for natives implemented in JavaScript really
5074 // efficient, we generate special code for expressions of the form:
5075 // 'typeof <expression> == <string>'.
5076 UnaryOperation* operation = left->AsUnaryOperation();
5077 if ((op == Token::EQ || op == Token::EQ_STRICT) &&
5078 (operation != NULL && operation->op() == Token::TYPEOF) &&
5079 (right->AsLiteral() != NULL &&
5080 right->AsLiteral()->handle()->IsString())) {
5081 Handle<String> check(String::cast(*right->AsLiteral()->handle()));
5082
5083 // Load the operand and move it to a register.
5084 LoadTypeofExpression(operation->expression());
5085 Result answer = frame_->Pop();
5086 answer.ToRegister();
5087
5088 if (check->Equals(Heap::number_symbol())) {
5089 __ test(answer.reg(), Immediate(kSmiTagMask));
5090 destination()->true_target()->Branch(zero);
5091 frame_->Spill(answer.reg());
5092 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
5093 __ cmp(answer.reg(), Factory::heap_number_map());
5094 answer.Unuse();
5095 destination()->Split(equal);
5096
5097 } else if (check->Equals(Heap::string_symbol())) {
5098 __ test(answer.reg(), Immediate(kSmiTagMask));
5099 destination()->false_target()->Branch(zero);
5100
5101 // It can be an undetectable string object.
5102 Result temp = allocator()->Allocate();
5103 ASSERT(temp.is_valid());
5104 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
5105 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset));
5106 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
5107 destination()->false_target()->Branch(not_zero);
5108 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
5109 __ movzx_b(temp.reg(),
5110 FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
5111 __ cmp(temp.reg(), FIRST_NONSTRING_TYPE);
5112 temp.Unuse();
5113 answer.Unuse();
5114 destination()->Split(less);
5115
5116 } else if (check->Equals(Heap::boolean_symbol())) {
5117 __ cmp(answer.reg(), Factory::true_value());
5118 destination()->true_target()->Branch(equal);
5119 __ cmp(answer.reg(), Factory::false_value());
5120 answer.Unuse();
5121 destination()->Split(equal);
5122
5123 } else if (check->Equals(Heap::undefined_symbol())) {
5124 __ cmp(answer.reg(), Factory::undefined_value());
5125 destination()->true_target()->Branch(equal);
5126
5127 __ test(answer.reg(), Immediate(kSmiTagMask));
5128 destination()->false_target()->Branch(zero);
5129
5130 // It can be an undetectable object.
5131 frame_->Spill(answer.reg());
5132 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
5133 __ movzx_b(answer.reg(),
5134 FieldOperand(answer.reg(), Map::kBitFieldOffset));
5135 __ test(answer.reg(), Immediate(1 << Map::kIsUndetectable));
5136 answer.Unuse();
5137 destination()->Split(not_zero);
5138
5139 } else if (check->Equals(Heap::function_symbol())) {
5140 __ test(answer.reg(), Immediate(kSmiTagMask));
5141 destination()->false_target()->Branch(zero);
5142 frame_->Spill(answer.reg());
5143 __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg());
5144 answer.Unuse();
5145 destination()->Split(equal);
5146
5147 } else if (check->Equals(Heap::object_symbol())) {
5148 __ test(answer.reg(), Immediate(kSmiTagMask));
5149 destination()->false_target()->Branch(zero);
5150 __ cmp(answer.reg(), Factory::null_value());
5151 destination()->true_target()->Branch(equal);
5152
5153 // It can be an undetectable object.
5154 Result map = allocator()->Allocate();
5155 ASSERT(map.is_valid());
5156 __ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
5157 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset));
5158 __ test(map.reg(), Immediate(1 << Map::kIsUndetectable));
5159 destination()->false_target()->Branch(not_zero);
5160 __ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
5161 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset));
5162 __ cmp(map.reg(), FIRST_JS_OBJECT_TYPE);
5163 destination()->false_target()->Branch(less);
5164 __ cmp(map.reg(), LAST_JS_OBJECT_TYPE);
5165 answer.Unuse();
5166 map.Unuse();
5167 destination()->Split(less_equal);
5168 } else {
5169 // Uncommon case: typeof testing against a string literal that is
5170 // never returned from the typeof operator.
5171 answer.Unuse();
5172 destination()->Goto(false);
5173 }
5174 return;
5175 }
5176
5177 Condition cc = no_condition;
5178 bool strict = false;
5179 switch (op) {
5180 case Token::EQ_STRICT:
5181 strict = true;
5182 // Fall through
5183 case Token::EQ:
5184 cc = equal;
5185 break;
5186 case Token::LT:
5187 cc = less;
5188 break;
5189 case Token::GT:
5190 cc = greater;
5191 break;
5192 case Token::LTE:
5193 cc = less_equal;
5194 break;
5195 case Token::GTE:
5196 cc = greater_equal;
5197 break;
5198 case Token::IN: {
5199 Load(left);
5200 Load(right);
5201 Result answer = frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2);
5202 frame_->Push(&answer); // push the result
5203 return;
5204 }
5205 case Token::INSTANCEOF: {
5206 Load(left);
5207 Load(right);
5208 InstanceofStub stub;
5209 Result answer = frame_->CallStub(&stub, 2);
5210 answer.ToRegister();
5211 __ test(answer.reg(), Operand(answer.reg()));
5212 answer.Unuse();
5213 destination()->Split(zero);
5214 return;
5215 }
5216 default:
5217 UNREACHABLE();
5218 }
5219 Load(left);
5220 Load(right);
5221 Comparison(cc, strict, destination());
5222 }
5223
5224
5225 #ifdef DEBUG
5226 bool CodeGenerator::HasValidEntryRegisters() {
5227 return (allocator()->count(eax) == (frame()->is_used(eax) ? 1 : 0))
5228 && (allocator()->count(ebx) == (frame()->is_used(ebx) ? 1 : 0))
5229 && (allocator()->count(ecx) == (frame()->is_used(ecx) ? 1 : 0))
5230 && (allocator()->count(edx) == (frame()->is_used(edx) ? 1 : 0))
5231 && (allocator()->count(edi) == (frame()->is_used(edi) ? 1 : 0));
5232 }
5233 #endif
5234
5235
5236 class DeferredReferenceGetKeyedValue: public DeferredCode {
5237 public:
5238 DeferredReferenceGetKeyedValue(CodeGenerator* generator, bool is_global)
5239 : DeferredCode(generator), is_global_(is_global) {
5240 set_comment("[ DeferredReferenceGetKeyedValue");
5241 }
5242
5243 virtual void Generate();
5244
5245 Label* patch_site() { return &patch_site_; }
5246
5247 private:
5248 Label patch_site_;
5249 bool is_global_;
5250 };
5251
5252
5253 void DeferredReferenceGetKeyedValue::Generate() {
5254 CodeGenerator* cgen = generator();
5255 Result receiver(cgen);
5256 Result key(cgen);
5257 enter()->Bind(&receiver, &key);
5258 cgen->frame()->Push(&receiver); // First IC argument.
5259 cgen->frame()->Push(&key); // Second IC argument.
5260
5261 // Calculate the delta from the IC call instruction to the map check
5262 // cmp instruction in the inlined version. This delta is stored in
5263 // a test(eax, delta) instruction after the call so that we can find
5264 // it in the IC initialization code and patch the cmp instruction.
5265 // This means that we cannot allow test instructions after calls to
5266 // KeyedLoadIC stubs in other places.
5267 RelocInfo::Mode mode = is_global_
5268 ? RelocInfo::CODE_TARGET_CONTEXT
5269 : RelocInfo::CODE_TARGET;
5270 Result value = cgen->frame()->CallKeyedLoadIC(mode);
5271 // The result needs to be specifically the eax register because the
5272 // offset to the patch site will be expected in a test eax
5273 // instruction.
5274 ASSERT(value.is_register() && value.reg().is(eax));
5275 // The delta from the start of the map-compare instruction to the
5276 // test eax instruction. We use masm_ directly here instead of the
5277 // double underscore macro because the macro sometimes uses macro
5278 // expansion to turn into something that can't return a value. This
5279 // is encountered when doing generated code coverage tests.
5280 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site());
5281 __ test(value.reg(), Immediate(-delta_to_patch_site));
5282 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1);
5283
5284 // The receiver and key were spilled by the call, so their state as
5285 // constants or copies has been changed. Thus, they need to be
5286 // "mergable" in the block at the exit label and are therefore
5287 // passed as return results here.
5288 key = cgen->frame()->Pop();
5289 receiver = cgen->frame()->Pop();
5290 exit_.Jump(&receiver, &key, &value);
5291 }
5292
5293
5294 #undef __
5295 #define __ ACCESS_MASM(masm)
5296
5297 Handle<String> Reference::GetName() {
5298 ASSERT(type_ == NAMED);
5299 Property* property = expression_->AsProperty();
5300 if (property == NULL) {
5301 // Global variable reference treated as a named property reference.
5302 VariableProxy* proxy = expression_->AsVariableProxy();
5303 ASSERT(proxy->AsVariable() != NULL);
5304 ASSERT(proxy->AsVariable()->is_global());
5305 return proxy->name();
5306 } else {
5307 Literal* raw_name = property->key()->AsLiteral();
5308 ASSERT(raw_name != NULL);
5309 return Handle<String>(String::cast(*raw_name->handle()));
5310 }
5311 }
5312
5313
5314 void Reference::GetValue(TypeofState typeof_state) {
5315 ASSERT(!cgen_->in_spilled_code());
5316 ASSERT(cgen_->HasValidEntryRegisters());
5317 ASSERT(!is_illegal());
5318 MacroAssembler* masm = cgen_->masm();
5319 switch (type_) {
5320 case SLOT: {
5321 Comment cmnt(masm, "[ Load from Slot");
5322 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
5323 ASSERT(slot != NULL);
5324 cgen_->LoadFromSlot(slot, typeof_state);
5325 break;
5326 }
5327
5328 case NAMED: {
5329 // TODO(1241834): Make sure that it is safe to ignore the
5330 // distinction between expressions in a typeof and not in a
5331 // typeof. If there is a chance that reference errors can be
5332 // thrown below, we must distinguish between the two kinds of
5333 // loads (typeof expression loads must not throw a reference
5334 // error).
5335 Comment cmnt(masm, "[ Load from named Property");
5336 cgen_->frame()->Push(GetName());
5337
5338 Variable* var = expression_->AsVariableProxy()->AsVariable();
5339 ASSERT(var == NULL || var->is_global());
5340 RelocInfo::Mode mode = (var == NULL)
5341 ? RelocInfo::CODE_TARGET
5342 : RelocInfo::CODE_TARGET_CONTEXT;
5343 Result answer = cgen_->frame()->CallLoadIC(mode);
5344 cgen_->frame()->Push(&answer);
5345 break;
5346 }
5347
5348 case KEYED: {
5349 // TODO(1241834): Make sure that this it is safe to ignore the
5350 // distinction between expressions in a typeof and not in a typeof.
5351 Comment cmnt(masm, "[ Load from keyed Property");
5352 Variable* var = expression_->AsVariableProxy()->AsVariable();
5353 bool is_global = var != NULL;
5354 ASSERT(!is_global || var->is_global());
5355 // Inline array load code if inside of a loop. We do not know
5356 // the receiver map yet, so we initially generate the code with
5357 // a check against an invalid map. In the inline cache code, we
5358 // patch the map check if appropriate.
5359 if (cgen_->loop_nesting() > 0) {
5360 Comment cmnt(masm, "[ Inlined array index load");
5361 DeferredReferenceGetKeyedValue* deferred =
5362 new DeferredReferenceGetKeyedValue(cgen_, is_global);
5363
5364 Result key = cgen_->frame()->Pop();
5365 Result receiver = cgen_->frame()->Pop();
5366 key.ToRegister();
5367 receiver.ToRegister();
5368
5369 // Check that the receiver is not a smi (only needed if this
5370 // is not a load from the global context) and that it has the
5371 // expected map.
5372 if (!is_global) {
5373 __ test(receiver.reg(), Immediate(kSmiTagMask));
5374 deferred->enter()->Branch(zero, &receiver, &key, not_taken);
5375 }
5376
5377 // Initially, use an invalid map. The map is patched in the IC
5378 // initialization code.
5379 __ bind(deferred->patch_site());
5380 // Use masm-> here instead of the double underscore macro since extra
5381 // coverage code can interfere with the patching.
5382 masm->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
5383 Immediate(Factory::null_value()));
5384 deferred->enter()->Branch(not_equal, &receiver, &key, not_taken);
5385
5386 // Check that the key is a smi.
5387 __ test(key.reg(), Immediate(kSmiTagMask));
5388 deferred->enter()->Branch(not_zero, &receiver, &key, not_taken);
5389
5390 // Get the elements array from the receiver and check that it
5391 // is not a dictionary.
5392 Result elements = cgen_->allocator()->Allocate();
5393 ASSERT(elements.is_valid());
5394 __ mov(elements.reg(),
5395 FieldOperand(receiver.reg(), JSObject::kElementsOffset));
5396 __ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset),
5397 Immediate(Factory::hash_table_map()));
5398 deferred->enter()->Branch(equal, &receiver, &key, not_taken);
5399
5400 // Shift the key to get the actual index value and check that
5401 // it is within bounds.
5402 Result index = cgen_->allocator()->Allocate();
5403 ASSERT(index.is_valid());
5404 __ mov(index.reg(), key.reg());
5405 __ sar(index.reg(), kSmiTagSize);
5406 __ cmp(index.reg(),
5407 FieldOperand(elements.reg(), Array::kLengthOffset));
5408 deferred->enter()->Branch(above_equal, &receiver, &key, not_taken);
5409
5410 // Load and check that the result is not the hole. We could
5411 // reuse the index or elements register for the value.
5412 //
5413 // TODO(206): Consider whether it makes sense to try some
5414 // heuristic about which register to reuse. For example, if
5415 // one is eax, the we can reuse that one because the value
5416 // coming from the deferred code will be in eax.
5417 Result value = index;
5418 __ mov(value.reg(), Operand(elements.reg(),
5419 index.reg(),
5420 times_4,
5421 Array::kHeaderSize - kHeapObjectTag));
5422 elements.Unuse();
5423 index.Unuse();
5424 __ cmp(Operand(value.reg()), Immediate(Factory::the_hole_value()));
5425 deferred->enter()->Branch(equal, &receiver, &key, not_taken);
5426 __ IncrementCounter(&Counters::keyed_load_inline, 1);
5427
5428 // Restore the receiver and key to the frame and push the
5429 // result on top of it.
5430 deferred->BindExit(&receiver, &key, &value);
5431 cgen_->frame()->Push(&receiver);
5432 cgen_->frame()->Push(&key);
5433 cgen_->frame()->Push(&value);
5434
5435 } else {
5436 Comment cmnt(masm, "[ Load from keyed Property");
5437 RelocInfo::Mode mode = is_global
5438 ? RelocInfo::CODE_TARGET_CONTEXT
5439 : RelocInfo::CODE_TARGET;
5440 Result answer = cgen_->frame()->CallKeyedLoadIC(mode);
5441 // Make sure that we do not have a test instruction after the
5442 // call. A test instruction after the call is used to
5443 // indicate that we have generated an inline version of the
5444 // keyed load. The explicit nop instruction is here because
5445 // the push that follows might be peep-hole optimized away.
5446 __ nop();
5447 cgen_->frame()->Push(&answer);
5448 }
5449 break;
5450 }
5451
5452 default:
5453 UNREACHABLE();
5454 }
5455 }
5456
5457
5458 void Reference::TakeValue(TypeofState typeof_state) {
5459 // For non-constant frame-allocated slots, we invalidate the value in the
5460 // slot. For all others, we fall back on GetValue.
5461 ASSERT(!cgen_->in_spilled_code());
5462 ASSERT(!is_illegal());
5463 if (type_ != SLOT) {
5464 GetValue(typeof_state);
5465 return;
5466 }
5467
5468 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
5469 ASSERT(slot != NULL);
5470 if (slot->type() == Slot::LOOKUP ||
5471 slot->type() == Slot::CONTEXT ||
5472 slot->var()->mode() == Variable::CONST) {
5473 GetValue(typeof_state);
5474 return;
5475 }
5476
5477 // Only non-constant, frame-allocated parameters and locals can reach
5478 // here.
5479 if (slot->type() == Slot::PARAMETER) {
5480 cgen_->frame()->TakeParameterAt(slot->index());
5481 } else {
5482 ASSERT(slot->type() == Slot::LOCAL);
5483 cgen_->frame()->TakeLocalAt(slot->index());
5484 }
5485 }
5486
5487
5488 void Reference::SetValue(InitState init_state) {
5489 ASSERT(cgen_->HasValidEntryRegisters());
5490 ASSERT(!is_illegal());
5491 switch (type_) {
5492 case SLOT: {
5493 Comment cmnt(cgen_->masm(), "[ Store to Slot");
5494 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
5495 ASSERT(slot != NULL);
5496 cgen_->StoreToSlot(slot, init_state);
5497 break;
5498 }
5499
5500 case NAMED: {
5501 Comment cmnt(cgen_->masm(), "[ Store to named Property");
5502 cgen_->frame()->Push(GetName());
5503 Result answer = cgen_->frame()->CallStoreIC();
5504 cgen_->frame()->Push(&answer);
5505 break;
5506 }
5507
5508 case KEYED: {
5509 Comment cmnt(cgen_->masm(), "[ Store to keyed Property");
5510 Result answer = cgen_->frame()->CallKeyedStoreIC();
5511 cgen_->frame()->Push(&answer);
5512 break;
5513 }
5514
5515 default:
5516 UNREACHABLE();
5517 }
5518 }
5519
5520
5521 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined).
5522 void ToBooleanStub::Generate(MacroAssembler* masm) {
5523 Label false_result, true_result, not_string;
5524 __ mov(eax, Operand(esp, 1 * kPointerSize));
5525
5526 // 'null' => false.
5527 __ cmp(eax, Factory::null_value());
5528 __ j(equal, &false_result);
5529
5530 // Get the map and type of the heap object.
5531 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
5532 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
5533
5534 // Undetectable => false.
5535 __ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset));
5536 __ and_(ebx, 1 << Map::kIsUndetectable);
5537 __ j(not_zero, &false_result);
5538
5539 // JavaScript object => true.
5540 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
5541 __ j(above_equal, &true_result);
5542
5543 // String value => false iff empty.
5544 __ cmp(ecx, FIRST_NONSTRING_TYPE);
5545 __ j(above_equal, &not_string);
5546 __ and_(ecx, kStringSizeMask);
5547 __ cmp(ecx, kShortStringTag);
5548 __ j(not_equal, &true_result); // Empty string is always short.
5549 __ mov(edx, FieldOperand(eax, String::kLengthOffset));
5550 __ shr(edx, String::kShortLengthShift);
5551 __ j(zero, &false_result);
5552 __ jmp(&true_result);
5553
5554 __ bind(&not_string);
5555 // HeapNumber => false iff +0, -0, or NaN.
5556 __ cmp(edx, Factory::heap_number_map());
5557 __ j(not_equal, &true_result);
5558 __ fldz();
5559 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
5560 __ fucompp();
5561 __ push(eax);
5562 __ fnstsw_ax();
5563 __ sahf();
5564 __ pop(eax);
5565 __ j(zero, &false_result);
5566 // Fall through to |true_result|.
5567
5568 // Return 1/0 for true/false in eax.
5569 __ bind(&true_result);
5570 __ mov(eax, 1);
5571 __ ret(1 * kPointerSize);
5572 __ bind(&false_result);
5573 __ mov(eax, 0);
5574 __ ret(1 * kPointerSize);
5575 }
5576
5577
5578 #undef __
5579 #define __ ACCESS_MASM(masm_)
5580
5581 Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left,
5582 Result* right) {
5583 // Perform fast-case smi code for the operation (left <op> right) and
5584 // returns the result in a Result.
5585 // If any fast-case tests fail, it jumps to the slow-case deferred code,
5586 // which calls the binary operation stub, with the arguments (in registers)
5587 // on top of the frame.
5588 // Consumes its arguments (sets left and right to invalid and frees their
5589 // registers).
5590
5591 left->ToRegister();
5592 right->ToRegister();
5593 // A newly allocated register answer is used to hold the answer.
5594 // The registers containing left and right are not modified in
5595 // most cases, so they usually don't need to be spilled in the fast case.
5596 Result answer = generator()->allocator()->Allocate();
5597
5598 ASSERT(answer.is_valid());
5599 // Perform the smi check.
5600 if (left->reg().is(right->reg())) {
5601 __ test(left->reg(), Immediate(kSmiTagMask));
5602 } else {
5603 __ mov(answer.reg(), left->reg());
5604 __ or_(answer.reg(), Operand(right->reg()));
5605 ASSERT(kSmiTag == 0); // adjust zero check if not the case
5606 __ test(answer.reg(), Immediate(kSmiTagMask));
5607 }
5608 enter()->Branch(not_zero, left, right, not_taken);
5609
5610 // All operations start by copying the left argument into answer.
5611 __ mov(answer.reg(), left->reg());
5612 switch (op_) {
5613 case Token::ADD:
5614 __ add(answer.reg(), Operand(right->reg())); // add optimistically
5615 enter()->Branch(overflow, left, right, not_taken);
5616 break;
5617
5618 case Token::SUB:
5619 __ sub(answer.reg(), Operand(right->reg())); // subtract optimistically
5620 enter()->Branch(overflow, left, right, not_taken);
5621 break;
5622
5623 case Token::MUL: {
5624 // If the smi tag is 0 we can just leave the tag on one operand.
5625 ASSERT(kSmiTag == 0); // adjust code below if not the case
5626 // Remove tag from the left operand (but keep sign).
5627 // Left hand operand has been copied into answer.
5628 __ sar(answer.reg(), kSmiTagSize);
5629 // Do multiplication of smis, leaving result in answer.
5630 __ imul(answer.reg(), Operand(right->reg()));
5631 // Go slow on overflows.
5632 enter()->Branch(overflow, left, right, not_taken);
5633 // Check for negative zero result. If product is zero,
5634 // and one argument is negative, go to slow case.
5635 // The frame is unchanged in this block, so local control flow can
5636 // use a Label rather than a JumpTarget.
5637 Label non_zero_result;
5638 __ test(answer.reg(), Operand(answer.reg()));
5639 __ j(not_zero, &non_zero_result, taken);
5640 __ mov(answer.reg(), left->reg());
5641 __ or_(answer.reg(), Operand(right->reg()));
5642 enter()->Branch(negative, left, right, not_taken);
5643 __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct.
5644 __ bind(&non_zero_result);
5645 break;
5646 }
5647
5648 case Token::DIV: // Fall through.
5649 case Token::MOD: {
5650 // Div and mod use the registers eax and edx. Left and right must
5651 // be preserved, because the original operands are needed if we switch
5652 // to the slow case. Move them if either is in eax or edx.
5653 // The Result answer should be changed into an alias for eax.
5654 // Precondition:
5655 // The Results left and right are valid. They may be the same register,
5656 // and may be unspilled. The Result answer is valid and is distinct
5657 // from left and right, and is spilled.
5658 // The value in left is copied to answer.
5659
5660 Result reg_eax = generator()->allocator()->Allocate(eax);
5661 Result reg_edx = generator()->allocator()->Allocate(edx);
5662 // These allocations may have failed, if one of left, right, or answer
5663 // is in register eax or edx.
5664 bool left_copied_to_eax = false; // We will make sure this becomes true.
5665
5666 // Part 1: Get eax
5667 if (answer.reg().is(eax)) {
5668 reg_eax = answer;
5669 left_copied_to_eax = true;
5670 } else if (right->reg().is(eax) || left->reg().is(eax)) {
5671 // We need a non-edx register to move one or both of left and right to.
5672 // We use answer if it is not edx, otherwise we allocate one.
5673 if (answer.reg().is(edx)) {
5674 reg_edx = answer;
5675 answer = generator()->allocator()->Allocate();
5676 ASSERT(answer.is_valid());
5677 }
5678
5679 if (left->reg().is(eax)) {
5680 reg_eax = *left;
5681 left_copied_to_eax = true;
5682 *left = answer;
5683 }
5684 if (right->reg().is(eax)) {
5685 reg_eax = *right;
5686 *right = answer;
5687 }
5688 __ mov(answer.reg(), eax);
5689 }
5690 // End of Part 1.
5691 // reg_eax is valid, and neither left nor right is in eax.
5692 ASSERT(reg_eax.is_valid());
5693 ASSERT(!left->reg().is(eax));
5694 ASSERT(!right->reg().is(eax));
5695
5696 // Part 2: Get edx
5697 // reg_edx is invalid if and only if either left, right,
5698 // or answer is in edx. If edx is valid, then either edx
5699 // was free, or it was answer, but answer was reallocated.
5700 if (answer.reg().is(edx)) {
5701 reg_edx = answer;
5702 } else if (right->reg().is(edx) || left->reg().is(edx)) {
5703 // Is answer used?
5704 if (answer.reg().is(eax) || answer.reg().is(left->reg()) ||
5705 answer.reg().is(right->reg())) {
5706 answer = generator()->allocator()->Allocate();
5707 ASSERT(answer.is_valid()); // We cannot hit both Allocate() calls.
5708 }
5709 if (left->reg().is(edx)) {
5710 reg_edx = *left;
5711 *left = answer;
5712 }
5713 if (right->reg().is(edx)) {
5714 reg_edx = *right;
5715 *right = answer;
5716 }
5717 __ mov(answer.reg(), edx);
5718 }
5719 // End of Part 2
5720 ASSERT(reg_edx.is_valid());
5721 ASSERT(!left->reg().is(eax));
5722 ASSERT(!right->reg().is(eax));
5723
5724 answer = reg_eax; // May free answer, if it was never used.
5725 generator()->frame()->Spill(eax);
5726 if (!left_copied_to_eax) {
5727 __ mov(eax, left->reg());
5728 left_copied_to_eax = true;
5729 }
5730 generator()->frame()->Spill(edx);
5731
5732 // Postcondition:
5733 // reg_eax, reg_edx are valid, correct, and spilled.
5734 // reg_eax contains the value originally in left
5735 // left and right are not eax or edx. They may or may not be
5736 // spilled or distinct.
5737 // answer is an alias for reg_eax.
5738
5739 // Sign extend eax into edx:eax.
5740 __ cdq();
5741 // Check for 0 divisor.
5742 __ test(right->reg(), Operand(right->reg()));
5743 enter()->Branch(zero, left, right, not_taken);
5744 // Divide edx:eax by the right operand.
5745 __ idiv(right->reg());
5746 if (op_ == Token::DIV) {
5747 // Check for negative zero result. If result is zero, and divisor
5748 // is negative, return a floating point negative zero.
5749 // The frame is unchanged in this block, so local control flow can
5750 // use a Label rather than a JumpTarget.
5751 Label non_zero_result;
5752 __ test(left->reg(), Operand(left->reg()));
5753 __ j(not_zero, &non_zero_result, taken);
5754 __ test(right->reg(), Operand(right->reg()));
5755 enter()->Branch(negative, left, right, not_taken);
5756 __ bind(&non_zero_result);
5757 // Check for the corner case of dividing the most negative smi
5758 // by -1. We cannot use the overflow flag, since it is not set
5759 // by idiv instruction.
5760 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
5761 __ cmp(eax, 0x40000000);
5762 enter()->Branch(equal, left, right, not_taken);
5763 // Check that the remainder is zero.
5764 __ test(edx, Operand(edx));
5765 enter()->Branch(not_zero, left, right, not_taken);
5766 // Tag the result and store it in register temp.
5767 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
5768 __ lea(answer.reg(), Operand(eax, eax, times_1, kSmiTag));
5769 } else {
5770 ASSERT(op_ == Token::MOD);
5771 // Check for a negative zero result. If the result is zero, and the
5772 // dividend is negative, return a floating point negative zero.
5773 // The frame is unchanged in this block, so local control flow can
5774 // use a Label rather than a JumpTarget.
5775 Label non_zero_result;
5776 __ test(edx, Operand(edx));
5777 __ j(not_zero, &non_zero_result, taken);
5778 __ test(left->reg(), Operand(left->reg()));
5779 enter()->Branch(negative, left, right, not_taken);
5780 __ bind(&non_zero_result);
5781 // The answer is in edx.
5782 answer = reg_edx;
5783 }
5784 break;
5785 }
5786 case Token::BIT_OR:
5787 __ or_(answer.reg(), Operand(right->reg()));
5788 break;
5789
5790 case Token::BIT_AND:
5791 __ and_(answer.reg(), Operand(right->reg()));
5792 break;
5793
5794 case Token::BIT_XOR:
5795 __ xor_(answer.reg(), Operand(right->reg()));
5796 break;
5797
5798 case Token::SHL:
5799 case Token::SHR:
5800 case Token::SAR:
5801 // Move right into ecx.
5802 // Left is in two registers already, so even if left or answer is ecx,
5803 // we can move right to it, and use the other one.
5804 // Right operand must be in register cl because x86 likes it that way.
5805 if (right->reg().is(ecx)) {
5806 // Right is already in the right place. Left may be in the
5807 // same register, which causes problems. Use answer instead.
5808 if (left->reg().is(ecx)) {
5809 *left = answer;
5810 }
5811 } else if (left->reg().is(ecx)) {
5812 generator()->frame()->Spill(left->reg());
5813 __ mov(left->reg(), right->reg());
5814 *right = *left;
5815 *left = answer; // Use copy of left in answer as left.
5816 } else if (answer.reg().is(ecx)) {
5817 __ mov(answer.reg(), right->reg());
5818 *right = answer;
5819 } else {
5820 Result reg_ecx = generator()->allocator()->Allocate(ecx);
5821 ASSERT(reg_ecx.is_valid());
5822 __ mov(ecx, right->reg());
5823 *right = reg_ecx;
5824 }
5825 ASSERT(left->reg().is_valid());
5826 ASSERT(!left->reg().is(ecx));
5827 ASSERT(right->reg().is(ecx));
5828 answer.Unuse(); // Answer may now be being used for left or right.
5829 // We will modify left and right, which we do not do in any other
5830 // binary operation. The exits to slow code need to restore the
5831 // original values of left and right, or at least values that give
5832 // the same answer.
5833
5834 // We are modifying left and right. They must be spilled!
5835 generator()->frame()->Spill(left->reg());
5836 generator()->frame()->Spill(right->reg());
5837
5838 // Remove tags from operands (but keep sign).
5839 __ sar(left->reg(), kSmiTagSize);
5840 __ sar(ecx, kSmiTagSize);
5841 // Perform the operation.
5842 switch (op_) {
5843 case Token::SAR:
5844 __ sar(left->reg());
5845 // No checks of result necessary
5846 break;
5847 case Token::SHR: {
5848 __ shr(left->reg());
5849 // Check that the *unsigned* result fits in a smi.
5850 // Neither of the two high-order bits can be set:
5851 // - 0x80000000: high bit would be lost when smi tagging.
5852 // - 0x40000000: this number would convert to negative when
5853 // Smi tagging these two cases can only happen with shifts
5854 // by 0 or 1 when handed a valid smi.
5855 // If the answer cannot be represented by a SMI, restore
5856 // the left and right arguments, and jump to slow case.
5857 // The low bit of the left argument may be lost, but only
5858 // in a case where it is dropped anyway.
5859 JumpTarget result_ok(generator());
5860 __ test(left->reg(), Immediate(0xc0000000));
5861 result_ok.Branch(zero, left, taken);
5862 __ shl(left->reg());
5863 ASSERT(kSmiTag == 0);
5864 __ shl(left->reg(), kSmiTagSize);
5865 __ shl(right->reg(), kSmiTagSize);
5866 enter()->Jump(left, right);
5867 result_ok.Bind(left);
5868 break;
5869 }
5870 case Token::SHL: {
5871 __ shl(left->reg());
5872 // Check that the *signed* result fits in a smi.
5873 //
5874 // TODO(207): Can reduce registers from 4 to 3 by
5875 // preallocating ecx.
5876 JumpTarget result_ok(generator());
5877 Result smi_test_reg = generator()->allocator()->Allocate();
5878 ASSERT(smi_test_reg.is_valid());
5879 __ lea(smi_test_reg.reg(), Operand(left->reg(), 0x40000000));
5880 __ test(smi_test_reg.reg(), Immediate(0x80000000));
5881 smi_test_reg.Unuse();
5882 result_ok.Branch(zero, left, taken);
5883 __ shr(left->reg());
5884 ASSERT(kSmiTag == 0);
5885 __ shl(left->reg(), kSmiTagSize);
5886 __ shl(right->reg(), kSmiTagSize);
5887 enter()->Jump(left, right);
5888 result_ok.Bind(left);
5889 break;
5890 }
5891 default:
5892 UNREACHABLE();
5893 }
5894 // Smi-tag the result, in left, and make answer an alias for left->
5895 answer = *left;
5896 answer.ToRegister();
5897 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
5898 __ lea(answer.reg(),
5899 Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
5900 break;
5901
5902 default:
5903 UNREACHABLE();
5904 break;
5905 }
5906 left->Unuse();
5907 right->Unuse();
5908 return answer;
5909 }
5910
5911
5912 #undef __
5913 #define __ ACCESS_MASM(masm)
5914
5915 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
5916 // Perform fast-case smi code for the operation (eax <op> ebx) and
5917 // leave result in register eax.
5918
5919 // Prepare the smi check of both operands by or'ing them together
5920 // before checking against the smi mask.
5921 __ mov(ecx, Operand(ebx));
5922 __ or_(ecx, Operand(eax));
5923
5924 switch (op_) {
5925 case Token::ADD:
5926 __ add(eax, Operand(ebx)); // add optimistically
5927 __ j(overflow, slow, not_taken);
5928 break;
5929
5930 case Token::SUB:
5931 __ sub(eax, Operand(ebx)); // subtract optimistically
5932 __ j(overflow, slow, not_taken);
5933 break;
5934
5935 case Token::DIV:
5936 case Token::MOD:
5937 // Sign extend eax into edx:eax.
5938 __ cdq();
5939 // Check for 0 divisor.
5940 __ test(ebx, Operand(ebx));
5941 __ j(zero, slow, not_taken);
5942 break;
5943
5944 default:
5945 // Fall-through to smi check.
5946 break;
5947 }
5948
5949 // Perform the actual smi check.
5950 ASSERT(kSmiTag == 0); // adjust zero check if not the case
5951 __ test(ecx, Immediate(kSmiTagMask));
5952 __ j(not_zero, slow, not_taken);
5953
5954 switch (op_) {
5955 case Token::ADD:
5956 case Token::SUB:
5957 // Do nothing here.
5958 break;
5959
5960 case Token::MUL:
5961 // If the smi tag is 0 we can just leave the tag on one operand.
5962 ASSERT(kSmiTag == 0); // adjust code below if not the case
5963 // Remove tag from one of the operands (but keep sign).
5964 __ sar(eax, kSmiTagSize);
5965 // Do multiplication.
5966 __ imul(eax, Operand(ebx)); // multiplication of smis; result in eax
5967 // Go slow on overflows.
5968 __ j(overflow, slow, not_taken);
5969 // Check for negative zero result.
5970 __ NegativeZeroTest(eax, ecx, slow); // use ecx = x | y
5971 break;
5972
5973 case Token::DIV:
5974 // Divide edx:eax by ebx.
5975 __ idiv(ebx);
5976 // Check for the corner case of dividing the most negative smi
5977 // by -1. We cannot use the overflow flag, since it is not set
5978 // by idiv instruction.
5979 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
5980 __ cmp(eax, 0x40000000);
5981 __ j(equal, slow);
5982 // Check for negative zero result.
5983 __ NegativeZeroTest(eax, ecx, slow); // use ecx = x | y
5984 // Check that the remainder is zero.
5985 __ test(edx, Operand(edx));
5986 __ j(not_zero, slow);
5987 // Tag the result and store it in register eax.
5988 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
5989 __ lea(eax, Operand(eax, eax, times_1, kSmiTag));
5990 break;
5991
5992 case Token::MOD:
5993 // Divide edx:eax by ebx.
5994 __ idiv(ebx);
5995 // Check for negative zero result.
5996 __ NegativeZeroTest(edx, ecx, slow); // use ecx = x | y
5997 // Move remainder to register eax.
5998 __ mov(eax, Operand(edx));
5999 break;
6000
6001 case Token::BIT_OR:
6002 __ or_(eax, Operand(ebx));
6003 break;
6004
6005 case Token::BIT_AND:
6006 __ and_(eax, Operand(ebx));
6007 break;
6008
6009 case Token::BIT_XOR:
6010 __ xor_(eax, Operand(ebx));
6011 break;
6012
6013 case Token::SHL:
6014 case Token::SHR:
6015 case Token::SAR:
6016 // Move the second operand into register ecx.
6017 __ mov(ecx, Operand(ebx));
6018 // Remove tags from operands (but keep sign).
6019 __ sar(eax, kSmiTagSize);
6020 __ sar(ecx, kSmiTagSize);
6021 // Perform the operation.
6022 switch (op_) {
6023 case Token::SAR:
6024 __ sar(eax);
6025 // No checks of result necessary
6026 break;
6027 case Token::SHR:
6028 __ shr(eax);
6029 // Check that the *unsigned* result fits in a smi.
6030 // Neither of the two high-order bits can be set:
6031 // - 0x80000000: high bit would be lost when smi tagging.
6032 // - 0x40000000: this number would convert to negative when
6033 // Smi tagging these two cases can only happen with shifts
6034 // by 0 or 1 when handed a valid smi.
6035 __ test(eax, Immediate(0xc0000000));
6036 __ j(not_zero, slow, not_taken);
6037 break;
6038 case Token::SHL:
6039 __ shl(eax);
6040 // Check that the *signed* result fits in a smi.
6041 __ cmp(eax, 0xc0000000);
6042 __ j(sign, slow, not_taken);
6043 break;
6044 default:
6045 UNREACHABLE();
6046 }
6047 // Tag the result and store it in register eax.
6048 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
6049 __ lea(eax, Operand(eax, eax, times_1, kSmiTag));
6050 break;
6051
6052 default:
6053 UNREACHABLE();
6054 break;
6055 }
6056 }
6057
6058
6059 void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
6060 Label call_runtime;
6061
6062 if (flags_ == SMI_CODE_IN_STUB) {
6063 // The fast case smi code wasn't inlined in the stub caller
6064 // code. Generate it here to speed up common operations.
6065 Label slow;
6066 __ mov(ebx, Operand(esp, 1 * kPointerSize)); // get y
6067 __ mov(eax, Operand(esp, 2 * kPointerSize)); // get x
6068 GenerateSmiCode(masm, &slow);
6069 __ ret(2 * kPointerSize); // remove both operands
6070
6071 // Too bad. The fast case smi code didn't succeed.
6072 __ bind(&slow);
6073 }
6074
6075 // Setup registers.
6076 __ mov(eax, Operand(esp, 1 * kPointerSize)); // get y
6077 __ mov(edx, Operand(esp, 2 * kPointerSize)); // get x
6078
6079 // Floating point case.
6080 switch (op_) {
6081 case Token::ADD:
6082 case Token::SUB:
6083 case Token::MUL:
6084 case Token::DIV: {
6085 // eax: y
6086 // edx: x
6087 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
6088 // Fast-case: Both operands are numbers.
6089 // Allocate a heap number, if needed.
6090 Label skip_allocation;
6091 switch (mode_) {
6092 case OVERWRITE_LEFT:
6093 __ mov(eax, Operand(edx));
6094 // Fall through!
6095 case OVERWRITE_RIGHT:
6096 // If the argument in eax is already an object, we skip the
6097 // allocation of a heap number.
6098 __ test(eax, Immediate(kSmiTagMask));
6099 __ j(not_zero, &skip_allocation, not_taken);
6100 // Fall through!
6101 case NO_OVERWRITE:
6102 FloatingPointHelper::AllocateHeapNumber(masm,
6103 &call_runtime,
6104 ecx,
6105 edx);
6106 __ bind(&skip_allocation);
6107 break;
6108 default: UNREACHABLE();
6109 }
6110 FloatingPointHelper::LoadFloatOperands(masm, ecx);
6111
6112 switch (op_) {
6113 case Token::ADD: __ faddp(1); break;
6114 case Token::SUB: __ fsubp(1); break;
6115 case Token::MUL: __ fmulp(1); break;
6116 case Token::DIV: __ fdivp(1); break;
6117 default: UNREACHABLE();
6118 }
6119 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
6120 __ ret(2 * kPointerSize);
6121 }
6122 case Token::MOD: {
6123 // For MOD we go directly to runtime in the non-smi case.
6124 break;
6125 }
6126 case Token::BIT_OR:
6127 case Token::BIT_AND:
6128 case Token::BIT_XOR:
6129 case Token::SAR:
6130 case Token::SHL:
6131 case Token::SHR: {
6132 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
6133 FloatingPointHelper::LoadFloatOperands(masm, ecx);
6134
6135 Label skip_allocation, non_smi_result, operand_conversion_failure;
6136
6137 // Reserve space for converted numbers.
6138 __ sub(Operand(esp), Immediate(2 * kPointerSize));
6139
6140 bool use_sse3 = CpuFeatures::IsSupported(CpuFeatures::SSE3);
6141 if (use_sse3) {
6142 // Truncate the operands to 32-bit integers and check for
6143 // exceptions in doing so.
6144 CpuFeatures::Scope scope(CpuFeatures::SSE3);
6145 __ fisttp_s(Operand(esp, 0 * kPointerSize));
6146 __ fisttp_s(Operand(esp, 1 * kPointerSize));
6147 __ fnstsw_ax();
6148 __ test(eax, Immediate(1));
6149 __ j(not_zero, &operand_conversion_failure);
6150 } else {
6151 // Check if right operand is int32.
6152 __ fist_s(Operand(esp, 0 * kPointerSize));
6153 __ fild_s(Operand(esp, 0 * kPointerSize));
6154 __ fucompp();
6155 __ fnstsw_ax();
6156 __ sahf();
6157 __ j(not_zero, &operand_conversion_failure);
6158 __ j(parity_even, &operand_conversion_failure);
6159
6160 // Check if left operand is int32.
6161 __ fist_s(Operand(esp, 1 * kPointerSize));
6162 __ fild_s(Operand(esp, 1 * kPointerSize));
6163 __ fucompp();
6164 __ fnstsw_ax();
6165 __ sahf();
6166 __ j(not_zero, &operand_conversion_failure);
6167 __ j(parity_even, &operand_conversion_failure);
6168 }
6169
6170 // Get int32 operands and perform bitop.
6171 __ pop(ecx);
6172 __ pop(eax);
6173 switch (op_) {
6174 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break;
6175 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
6176 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
6177 case Token::SAR: __ sar(eax); break;
6178 case Token::SHL: __ shl(eax); break;
6179 case Token::SHR: __ shr(eax); break;
6180 default: UNREACHABLE();
6181 }
6182
6183 // Check if result is non-negative and fits in a smi.
6184 __ test(eax, Immediate(0xc0000000));
6185 __ j(not_zero, &non_smi_result);
6186
6187 // Tag smi result and return.
6188 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
6189 __ lea(eax, Operand(eax, eax, times_1, kSmiTag));
6190 __ ret(2 * kPointerSize);
6191
6192 // All ops except SHR return a signed int32 that we load in a HeapNumber.
6193 if (op_ != Token::SHR) {
6194 __ bind(&non_smi_result);
6195 // Allocate a heap number if needed.
6196 __ mov(ebx, Operand(eax)); // ebx: result
6197 switch (mode_) {
6198 case OVERWRITE_LEFT:
6199 case OVERWRITE_RIGHT:
6200 // If the operand was an object, we skip the
6201 // allocation of a heap number.
6202 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
6203 1 * kPointerSize : 2 * kPointerSize));
6204 __ test(eax, Immediate(kSmiTagMask));
6205 __ j(not_zero, &skip_allocation, not_taken);
6206 // Fall through!
6207 case NO_OVERWRITE:
6208 FloatingPointHelper::AllocateHeapNumber(masm, &call_runtime,
6209 ecx, edx);
6210 __ bind(&skip_allocation);
6211 break;
6212 default: UNREACHABLE();
6213 }
6214 // Store the result in the HeapNumber and return.
6215 __ mov(Operand(esp, 1 * kPointerSize), ebx);
6216 __ fild_s(Operand(esp, 1 * kPointerSize));
6217 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
6218 __ ret(2 * kPointerSize);
6219 }
6220
6221 // Clear the FPU exception flag and reset the stack before calling
6222 // the runtime system.
6223 __ bind(&operand_conversion_failure);
6224 __ add(Operand(esp), Immediate(2 * kPointerSize));
6225 if (use_sse3) {
6226 // If we've used the SSE3 instructions for truncating the
6227 // floating point values to integers and it failed, we have a
6228 // pending #IA exception. Clear it.
6229 __ fnclex();
6230 } else {
6231 // The non-SSE3 variant does early bailout if the right
6232 // operand isn't a 32-bit integer, so we may have a single
6233 // value on the FPU stack we need to get rid of.
6234 __ ffree(0);
6235 }
6236
6237 // SHR should return uint32 - go to runtime for non-smi/negative result.
6238 if (op_ == Token::SHR) {
6239 __ bind(&non_smi_result);
6240 }
6241 __ mov(eax, Operand(esp, 1 * kPointerSize));
6242 __ mov(edx, Operand(esp, 2 * kPointerSize));
6243 break;
6244 }
6245 default: UNREACHABLE(); break;
6246 }
6247
6248 // If all else fails, use the runtime system to get the correct
6249 // result.
6250 __ bind(&call_runtime);
6251 switch (op_) {
6252 case Token::ADD:
6253 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
6254 break;
6255 case Token::SUB:
6256 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
6257 break;
6258 case Token::MUL:
6259 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
6260 break;
6261 case Token::DIV:
6262 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
6263 break;
6264 case Token::MOD:
6265 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
6266 break;
6267 case Token::BIT_OR:
6268 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
6269 break;
6270 case Token::BIT_AND:
6271 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
6272 break;
6273 case Token::BIT_XOR:
6274 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
6275 break;
6276 case Token::SAR:
6277 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
6278 break;
6279 case Token::SHL:
6280 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
6281 break;
6282 case Token::SHR:
6283 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
6284 break;
6285 default:
6286 UNREACHABLE();
6287 }
6288 }
6289
6290
6291 void FloatingPointHelper::AllocateHeapNumber(MacroAssembler* masm,
6292 Label* need_gc,
6293 Register scratch1,
6294 Register scratch2) {
6295 ExternalReference allocation_top =
6296 ExternalReference::new_space_allocation_top_address();
6297 ExternalReference allocation_limit =
6298 ExternalReference::new_space_allocation_limit_address();
6299 __ mov(Operand(scratch1), Immediate(allocation_top));
6300 __ mov(eax, Operand(scratch1, 0));
6301 __ lea(scratch2, Operand(eax, HeapNumber::kSize)); // scratch2: new top
6302 __ cmp(scratch2, Operand::StaticVariable(allocation_limit));
6303 __ j(above, need_gc, not_taken);
6304
6305 __ mov(Operand(scratch1, 0), scratch2); // store new top
6306 __ mov(Operand(eax, HeapObject::kMapOffset),
6307 Immediate(Factory::heap_number_map()));
6308 // Tag old top and use as result.
6309 __ add(Operand(eax), Immediate(kHeapObjectTag));
6310 }
6311
6312
6313 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
6314 Register scratch) {
6315 Label load_smi_1, load_smi_2, done_load_1, done;
6316 __ mov(scratch, Operand(esp, 2 * kPointerSize));
6317 __ test(scratch, Immediate(kSmiTagMask));
6318 __ j(zero, &load_smi_1, not_taken);
6319 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
6320 __ bind(&done_load_1);
6321
6322 __ mov(scratch, Operand(esp, 1 * kPointerSize));
6323 __ test(scratch, Immediate(kSmiTagMask));
6324 __ j(zero, &load_smi_2, not_taken);
6325 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
6326 __ jmp(&done);
6327
6328 __ bind(&load_smi_1);
6329 __ sar(scratch, kSmiTagSize);
6330 __ push(scratch);
6331 __ fild_s(Operand(esp, 0));
6332 __ pop(scratch);
6333 __ jmp(&done_load_1);
6334
6335 __ bind(&load_smi_2);
6336 __ sar(scratch, kSmiTagSize);
6337 __ push(scratch);
6338 __ fild_s(Operand(esp, 0));
6339 __ pop(scratch);
6340
6341 __ bind(&done);
6342 }
6343
6344
6345 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm,
6346 Label* non_float,
6347 Register scratch) {
6348 Label test_other, done;
6349 // Test if both operands are floats or smi -> scratch=k_is_float;
6350 // Otherwise scratch = k_not_float.
6351 __ test(edx, Immediate(kSmiTagMask));
6352 __ j(zero, &test_other, not_taken); // argument in edx is OK
6353 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset));
6354 __ cmp(scratch, Factory::heap_number_map());
6355 __ j(not_equal, non_float); // argument in edx is not a number -> NaN
6356
6357 __ bind(&test_other);
6358 __ test(eax, Immediate(kSmiTagMask));
6359 __ j(zero, &done); // argument in eax is OK
6360 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset));
6361 __ cmp(scratch, Factory::heap_number_map());
6362 __ j(not_equal, non_float); // argument in eax is not a number -> NaN
6363
6364 // Fall-through: Both operands are numbers.
6365 __ bind(&done);
6366 }
6367
6368
6369 void UnarySubStub::Generate(MacroAssembler* masm) {
6370 Label undo;
6371 Label slow;
6372 Label done;
6373 Label try_float;
6374
6375 // Check whether the value is a smi.
6376 __ test(eax, Immediate(kSmiTagMask));
6377 __ j(not_zero, &try_float, not_taken);
6378
6379 // Enter runtime system if the value of the expression is zero
6380 // to make sure that we switch between 0 and -0.
6381 __ test(eax, Operand(eax));
6382 __ j(zero, &slow, not_taken);
6383
6384 // The value of the expression is a smi that is not zero. Try
6385 // optimistic subtraction '0 - value'.
6386 __ mov(edx, Operand(eax));
6387 __ Set(eax, Immediate(0));
6388 __ sub(eax, Operand(edx));
6389 __ j(overflow, &undo, not_taken);
6390
6391 // If result is a smi we are done.
6392 __ test(eax, Immediate(kSmiTagMask));
6393 __ j(zero, &done, taken);
6394
6395 // Restore eax and enter runtime system.
6396 __ bind(&undo);
6397 __ mov(eax, Operand(edx));
6398
6399 // Enter runtime system.
6400 __ bind(&slow);
6401 __ pop(ecx); // pop return address
6402 __ push(eax);
6403 __ push(ecx); // push return address
6404 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
6405
6406 // Try floating point case.
6407 __ bind(&try_float);
6408 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
6409 __ cmp(edx, Factory::heap_number_map());
6410 __ j(not_equal, &slow);
6411 __ mov(edx, Operand(eax));
6412 // edx: operand
6413 FloatingPointHelper::AllocateHeapNumber(masm, &undo, ebx, ecx);
6414 // eax: allocated 'empty' number
6415 __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
6416 __ fchs();
6417 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
6418
6419 __ bind(&done);
6420
6421 __ StubReturn(1);
6422 }
6423
6424
6425 void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
6426 // Check if the calling frame is an arguments adaptor frame.
6427 Label adaptor;
6428 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
6429 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
6430 __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
6431 __ j(equal, &adaptor);
6432
6433 // Nothing to do: The formal number of parameters has already been
6434 // passed in register eax by calling function. Just return it.
6435 __ ret(0);
6436
6437 // Arguments adaptor case: Read the arguments length from the
6438 // adaptor frame and return it.
6439 __ bind(&adaptor);
6440 __ mov(eax, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
6441 __ ret(0);
6442 }
6443
6444
6445 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
6446 // The key is in edx and the parameter count is in eax.
6447
6448 // The displacement is used for skipping the frame pointer on the
6449 // stack. It is the offset of the last parameter (if any) relative
6450 // to the frame pointer.
6451 static const int kDisplacement = 1 * kPointerSize;
6452
6453 // Check that the key is a smi.
6454 Label slow;
6455 __ test(edx, Immediate(kSmiTagMask));
6456 __ j(not_zero, &slow, not_taken);
6457
6458 // Check if the calling frame is an arguments adaptor frame.
6459 Label adaptor;
6460 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
6461 __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset));
6462 __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
6463 __ j(equal, &adaptor);
6464
6465 // Check index against formal parameters count limit passed in
6466 // through register eax. Use unsigned comparison to get negative
6467 // check for free.
6468 __ cmp(edx, Operand(eax));
6469 __ j(above_equal, &slow, not_taken);
6470
6471 // Read the argument from the stack and return it.
6472 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); // shifting code depends on this
6473 __ lea(ebx, Operand(ebp, eax, times_2, 0));
6474 __ neg(edx);
6475 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
6476 __ ret(0);
6477
6478 // Arguments adaptor case: Check index against actual arguments
6479 // limit found in the arguments adaptor frame. Use unsigned
6480 // comparison to get negative check for free.
6481 __ bind(&adaptor);
6482 __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
6483 __ cmp(edx, Operand(ecx));
6484 __ j(above_equal, &slow, not_taken);
6485
6486 // Read the argument from the stack and return it.
6487 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); // shifting code depends on this
6488 __ lea(ebx, Operand(ebx, ecx, times_2, 0));
6489 __ neg(edx);
6490 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
6491 __ ret(0);
6492
6493 // Slow-case: Handle non-smi or out-of-bounds access to arguments
6494 // by calling the runtime system.
6495 __ bind(&slow);
6496 __ pop(ebx); // Return address.
6497 __ push(edx);
6498 __ push(ebx);
6499 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
6500 }
6501
6502
6503 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
6504 // The displacement is used for skipping the return address and the
6505 // frame pointer on the stack. It is the offset of the last
6506 // parameter (if any) relative to the frame pointer.
6507 static const int kDisplacement = 2 * kPointerSize;
6508
6509 // Check if the calling frame is an arguments adaptor frame.
6510 Label runtime;
6511 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
6512 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
6513 __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
6514 __ j(not_equal, &runtime);
6515
6516 // Patch the arguments.length and the parameters pointer.
6517 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
6518 __ mov(Operand(esp, 1 * kPointerSize), ecx);
6519 __ lea(edx, Operand(edx, ecx, times_2, kDisplacement));
6520 __ mov(Operand(esp, 2 * kPointerSize), edx);
6521
6522 // Do the runtime call to allocate the arguments object.
6523 __ bind(&runtime);
6524 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
6525 }
6526
6527
6528 void CompareStub::Generate(MacroAssembler* masm) {
6529 Label call_builtin, done;
6530
6531 // NOTICE! This code is only reached after a smi-fast-case check, so
6532 // it is certain that at least one operand isn't a smi.
6533
6534 if (cc_ == equal) { // Both strict and non-strict.
6535 Label slow; // Fallthrough label.
6536 // Equality is almost reflexive (everything but NaN), so start by testing
6537 // for "identity and not NaN".
6538 {
6539 Label not_identical;
6540 __ cmp(eax, Operand(edx));
6541 __ j(not_equal, &not_identical);
6542 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
6543 // so we do the second best thing - test it ourselves.
6544
6545 Label return_equal;
6546 Label heap_number;
6547 // If it's not a heap number, then return equal.
6548 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
6549 Immediate(Factory::heap_number_map()));
6550 __ j(equal, &heap_number);
6551 __ bind(&return_equal);
6552 __ Set(eax, Immediate(0));
6553 __ ret(0);
6554
6555 __ bind(&heap_number);
6556 // It is a heap number, so return non-equal if it's NaN and equal if it's
6557 // not NaN.
6558 // The representation of NaN values has all exponent bits (52..62) set,
6559 // and not all mantissa bits (0..51) clear.
6560 // Read top bits of double representation (second word of value).
6561 __ mov(eax, FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize));
6562 // Test that exponent bits are all set.
6563 __ not_(eax);
6564 __ test(eax, Immediate(0x7ff00000));
6565 __ j(not_zero, &return_equal);
6566 __ not_(eax);
6567
6568 // Shift out flag and all exponent bits, retaining only mantissa.
6569 __ shl(eax, 12);
6570 // Or with all low-bits of mantissa.
6571 __ or_(eax, FieldOperand(edx, HeapNumber::kValueOffset));
6572 // Return zero equal if all bits in mantissa is zero (it's an Infinity)
6573 // and non-zero if not (it's a NaN).
6574 __ ret(0);
6575
6576 __ bind(&not_identical);
6577 }
6578
6579 // If we're doing a strict equality comparison, we don't have to do
6580 // type conversion, so we generate code to do fast comparison for objects
6581 // and oddballs. Non-smi numbers and strings still go through the usual
6582 // slow-case code.
6583 if (strict_) {
6584 // If either is a Smi (we know that not both are), then they can only
6585 // be equal if the other is a HeapNumber. If so, use the slow case.
6586 {
6587 Label not_smis;
6588 ASSERT_EQ(0, kSmiTag);
6589 ASSERT_EQ(0, Smi::FromInt(0));
6590 __ mov(ecx, Immediate(kSmiTagMask));
6591 __ and_(ecx, Operand(eax));
6592 __ test(ecx, Operand(edx));
6593 __ j(not_zero, &not_smis);
6594 // One operand is a smi.
6595
6596 // Check whether the non-smi is a heap number.
6597 ASSERT_EQ(1, kSmiTagMask);
6598 // ecx still holds eax & kSmiTag, which is either zero or one.
6599 __ sub(Operand(ecx), Immediate(0x01));
6600 __ mov(ebx, edx);
6601 __ xor_(ebx, Operand(eax));
6602 __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx.
6603 __ xor_(ebx, Operand(eax));
6604 // if eax was smi, ebx is now edx, else eax.
6605
6606 // Check if the non-smi operand is a heap number.
6607 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
6608 Immediate(Factory::heap_number_map()));
6609 // If heap number, handle it in the slow case.
6610 __ j(equal, &slow);
6611 // Return non-equal (ebx is not zero)
6612 __ mov(eax, ebx);
6613 __ ret(0);
6614
6615 __ bind(&not_smis);
6616 }
6617
6618 // If either operand is a JSObject or an oddball value, then they are not
6619 // equal since their pointers are different
6620 // There is no test for undetectability in strict equality.
6621
6622 // Get the type of the first operand.
6623 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
6624 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
6625
6626 // If the first object is a JS object, we have done pointer comparison.
6627 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
6628 Label first_non_object;
6629 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
6630 __ j(less, &first_non_object);
6631
6632 // Return non-zero (eax is not zero)
6633 Label return_not_equal;
6634 ASSERT(kHeapObjectTag != 0);
6635 __ bind(&return_not_equal);
6636 __ ret(0);
6637
6638 __ bind(&first_non_object);
6639 // Check for oddballs: true, false, null, undefined.
6640 __ cmp(ecx, ODDBALL_TYPE);
6641 __ j(equal, &return_not_equal);
6642
6643 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
6644 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
6645
6646 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
6647 __ j(greater_equal, &return_not_equal);
6648
6649 // Check for oddballs: true, false, null, undefined.
6650 __ cmp(ecx, ODDBALL_TYPE);
6651 __ j(equal, &return_not_equal);
6652
6653 // Fall through to the general case.
6654 }
6655 __ bind(&slow);
6656 }
6657
6658 // Save the return address (and get it off the stack).
6659 __ pop(ecx);
6660
6661 // Push arguments.
6662 __ push(eax);
6663 __ push(edx);
6664 __ push(ecx);
6665
6666 // Inlined floating point compare.
6667 // Call builtin if operands are not floating point or smi.
6668 FloatingPointHelper::CheckFloatOperands(masm, &call_builtin, ebx);
6669 FloatingPointHelper::LoadFloatOperands(masm, ecx);
6670 __ FCmp();
6671
6672 // Jump to builtin for NaN.
6673 __ j(parity_even, &call_builtin, not_taken);
6674
6675 // TODO(1243847): Use cmov below once CpuFeatures are properly hooked up.
6676 Label below_lbl, above_lbl;
6677 // use edx, eax to convert unsigned to signed comparison
6678 __ j(below, &below_lbl, not_taken);
6679 __ j(above, &above_lbl, not_taken);
6680
6681 __ xor_(eax, Operand(eax)); // equal
6682 __ ret(2 * kPointerSize);
6683
6684 __ bind(&below_lbl);
6685 __ mov(eax, -1);
6686 __ ret(2 * kPointerSize);
6687
6688 __ bind(&above_lbl);
6689 __ mov(eax, 1);
6690 __ ret(2 * kPointerSize); // eax, edx were pushed
6691
6692 __ bind(&call_builtin);
6693 // must swap argument order
6694 __ pop(ecx);
6695 __ pop(edx);
6696 __ pop(eax);
6697 __ push(edx);
6698 __ push(eax);
6699
6700 // Figure out which native to call and setup the arguments.
6701 Builtins::JavaScript builtin;
6702 if (cc_ == equal) {
6703 builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
6704 } else {
6705 builtin = Builtins::COMPARE;
6706 int ncr; // NaN compare result
6707 if (cc_ == less || cc_ == less_equal) {
6708 ncr = GREATER;
6709 } else {
6710 ASSERT(cc_ == greater || cc_ == greater_equal); // remaining cases
6711 ncr = LESS;
6712 }
6713 __ push(Immediate(Smi::FromInt(ncr)));
6714 }
6715
6716 // Restore return address on the stack.
6717 __ push(ecx);
6718
6719 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
6720 // tagged as a small integer.
6721 __ InvokeBuiltin(builtin, JUMP_FUNCTION);
6722 }
6723
6724
6725 void StackCheckStub::Generate(MacroAssembler* masm) {
6726 // Because builtins always remove the receiver from the stack, we
6727 // have to fake one to avoid underflowing the stack. The receiver
6728 // must be inserted below the return address on the stack so we
6729 // temporarily store that in a register.
6730 __ pop(eax);
6731 __ push(Immediate(Smi::FromInt(0)));
6732 __ push(eax);
6733
6734 // Do tail-call to runtime routine.
6735 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
6736 }
6737
6738
6739 void CallFunctionStub::Generate(MacroAssembler* masm) {
6740 Label slow;
6741
6742 // Get the function to call from the stack.
6743 // +2 ~ receiver, return address
6744 __ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize));
6745
6746 // Check that the function really is a JavaScript function.
6747 __ test(edi, Immediate(kSmiTagMask));
6748 __ j(zero, &slow, not_taken);
6749 // Goto slow case if we do not have a function.
6750 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
6751 __ j(not_equal, &slow, not_taken);
6752
6753 // Fast-case: Just invoke the function.
6754 ParameterCount actual(argc_);
6755 __ InvokeFunction(edi, actual, JUMP_FUNCTION);
6756
6757 // Slow-case: Non-function called.
6758 __ bind(&slow);
6759 __ Set(eax, Immediate(argc_));
6760 __ Set(ebx, Immediate(0));
6761 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
6762 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
6763 __ jmp(adaptor, RelocInfo::CODE_TARGET);
6764 }
6765
6766
6767
6768 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
6769 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code
6770 ExternalReference handler_address(Top::k_handler_address);
6771 __ mov(edx, Operand::StaticVariable(handler_address));
6772 __ mov(ecx, Operand(edx, -1 * kPointerSize)); // get next in chain
6773 __ mov(Operand::StaticVariable(handler_address), ecx);
6774 __ mov(esp, Operand(edx));
6775 __ pop(edi);
6776 __ pop(ebp);
6777 __ pop(edx); // remove code pointer
6778 __ pop(edx); // remove state
6779
6780 // Before returning we restore the context from the frame pointer if not NULL.
6781 // The frame pointer is NULL in the exception handler of a JS entry frame.
6782 __ xor_(esi, Operand(esi)); // tentatively set context pointer to NULL
6783 Label skip;
6784 __ cmp(ebp, 0);
6785 __ j(equal, &skip, not_taken);
6786 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
6787 __ bind(&skip);
6788
6789 __ ret(0);
6790 }
6791
6792
6793 void CEntryStub::GenerateCore(MacroAssembler* masm,
6794 Label* throw_normal_exception,
6795 Label* throw_out_of_memory_exception,
6796 StackFrame::Type frame_type,
6797 bool do_gc,
6798 bool always_allocate_scope) {
6799 // eax: result parameter for PerformGC, if any
6800 // ebx: pointer to C function (C callee-saved)
6801 // ebp: frame pointer (restored after C call)
6802 // esp: stack pointer (restored after C call)
6803 // edi: number of arguments including receiver (C callee-saved)
6804 // esi: pointer to the first argument (C callee-saved)
6805
6806 if (do_gc) {
6807 __ mov(Operand(esp, 0 * kPointerSize), eax); // Result.
6808 __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
6809 }
6810
6811 ExternalReference scope_depth =
6812 ExternalReference::heap_always_allocate_scope_depth();
6813 if (always_allocate_scope) {
6814 __ inc(Operand::StaticVariable(scope_depth));
6815 }
6816
6817 // Call C function.
6818 __ mov(Operand(esp, 0 * kPointerSize), edi); // argc.
6819 __ mov(Operand(esp, 1 * kPointerSize), esi); // argv.
6820 __ call(Operand(ebx));
6821 // Result is in eax or edx:eax - do not destroy these registers!
6822
6823 if (always_allocate_scope) {
6824 __ dec(Operand::StaticVariable(scope_depth));
6825 }
6826
6827 // Check for failure result.
6828 Label failure_returned;
6829 ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
6830 __ lea(ecx, Operand(eax, 1));
6831 // Lower 2 bits of ecx are 0 iff eax has failure tag.
6832 __ test(ecx, Immediate(kFailureTagMask));
6833 __ j(zero, &failure_returned, not_taken);
6834
6835 // Exit the JavaScript to C++ exit frame.
6836 __ LeaveExitFrame(frame_type);
6837 __ ret(0);
6838
6839 // Handling of failure.
6840 __ bind(&failure_returned);
6841
6842 Label retry;
6843 // If the returned exception is RETRY_AFTER_GC continue at retry label
6844 ASSERT(Failure::RETRY_AFTER_GC == 0);
6845 __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
6846 __ j(zero, &retry, taken);
6847
6848 Label continue_exception;
6849 // If the returned failure is EXCEPTION then promote Top::pending_exception().
6850 __ cmp(eax, reinterpret_cast<int32_t>(Failure::Exception()));
6851 __ j(not_equal, &continue_exception);
6852
6853 // Retrieve the pending exception and clear the variable.
6854 ExternalReference pending_exception_address(Top::k_pending_exception_address);
6855 __ mov(eax, Operand::StaticVariable(pending_exception_address));
6856 __ mov(edx,
6857 Operand::StaticVariable(ExternalReference::the_hole_value_location()));
6858 __ mov(Operand::StaticVariable(pending_exception_address), edx);
6859
6860 __ bind(&continue_exception);
6861 // Special handling of out of memory exception.
6862 __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
6863 __ j(equal, throw_out_of_memory_exception);
6864
6865 // Handle normal exception.
6866 __ jmp(throw_normal_exception);
6867
6868 // Retry.
6869 __ bind(&retry);
6870 }
6871
6872
6873 void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
6874 // Fetch top stack handler.
6875 ExternalReference handler_address(Top::k_handler_address);
6876 __ mov(edx, Operand::StaticVariable(handler_address));
6877
6878 // Unwind the handlers until the ENTRY handler is found.
6879 Label loop, done;
6880 __ bind(&loop);
6881 // Load the type of the current stack handler.
6882 const int kStateOffset = StackHandlerConstants::kAddressDisplacement +
6883 StackHandlerConstants::kStateOffset;
6884 __ cmp(Operand(edx, kStateOffset), Immediate(StackHandler::ENTRY));
6885 __ j(equal, &done);
6886 // Fetch the next handler in the list.
6887 const int kNextOffset = StackHandlerConstants::kAddressDisplacement +
6888 StackHandlerConstants::kNextOffset;
6889 __ mov(edx, Operand(edx, kNextOffset));
6890 __ jmp(&loop);
6891 __ bind(&done);
6892
6893 // Set the top handler address to next handler past the current ENTRY handler.
6894 __ mov(eax, Operand(edx, kNextOffset));
6895 __ mov(Operand::StaticVariable(handler_address), eax);
6896
6897 // Set external caught exception to false.
6898 __ mov(eax, false);
6899 ExternalReference external_caught(Top::k_external_caught_exception_address);
6900 __ mov(Operand::StaticVariable(external_caught), eax);
6901
6902 // Set pending exception and eax to out of memory exception.
6903 __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
6904 ExternalReference pending_exception(Top::k_pending_exception_address);
6905 __ mov(Operand::StaticVariable(pending_exception), eax);
6906
6907 // Restore the stack to the address of the ENTRY handler
6908 __ mov(esp, Operand(edx));
6909
6910 // Clear the context pointer;
6911 __ xor_(esi, Operand(esi));
6912
6913 // Restore registers from handler.
6914 __ pop(edi); // PP
6915 __ pop(ebp); // FP
6916 __ pop(edx); // Code
6917 __ pop(edx); // State
6918
6919 __ ret(0);
6920 }
6921
6922
6923 void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
6924 // eax: number of arguments including receiver
6925 // ebx: pointer to C function (C callee-saved)
6926 // ebp: frame pointer (restored after C call)
6927 // esp: stack pointer (restored after C call)
6928 // esi: current context (C callee-saved)
6929 // edi: caller's parameter pointer pp (C callee-saved)
6930
6931 // NOTE: Invocations of builtins may return failure objects
6932 // instead of a proper result. The builtin entry handles
6933 // this by performing a garbage collection and retrying the
6934 // builtin once.
6935
6936 StackFrame::Type frame_type = is_debug_break ?
6937 StackFrame::EXIT_DEBUG :
6938 StackFrame::EXIT;
6939
6940 // Enter the exit frame that transitions from JavaScript to C++.
6941 __ EnterExitFrame(frame_type);
6942
6943 // eax: result parameter for PerformGC, if any (setup below)
6944 // ebx: pointer to builtin function (C callee-saved)
6945 // ebp: frame pointer (restored after C call)
6946 // esp: stack pointer (restored after C call)
6947 // edi: number of arguments including receiver (C callee-saved)
6948 // esi: argv pointer (C callee-saved)
6949
6950 Label throw_out_of_memory_exception;
6951 Label throw_normal_exception;
6952
6953 // Call into the runtime system. Collect garbage before the call if
6954 // running with --gc-greedy set.
6955 if (FLAG_gc_greedy) {
6956 Failure* failure = Failure::RetryAfterGC(0);
6957 __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
6958 }
6959 GenerateCore(masm, &throw_normal_exception,
6960 &throw_out_of_memory_exception,
6961 frame_type,
6962 FLAG_gc_greedy,
6963 false);
6964
6965 // Do space-specific GC and retry runtime call.
6966 GenerateCore(masm,
6967 &throw_normal_exception,
6968 &throw_out_of_memory_exception,
6969 frame_type,
6970 true,
6971 false);
6972
6973 // Do full GC and retry runtime call one final time.
6974 Failure* failure = Failure::InternalError();
6975 __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
6976 GenerateCore(masm,
6977 &throw_normal_exception,
6978 &throw_out_of_memory_exception,
6979 frame_type,
6980 true,
6981 true);
6982
6983 __ bind(&throw_out_of_memory_exception);
6984 GenerateThrowOutOfMemory(masm);
6985 // control flow for generated will not return.
6986
6987 __ bind(&throw_normal_exception);
6988 GenerateThrowTOS(masm);
6989 }
6990
6991
6992 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
6993 Label invoke, exit;
6994
6995 // Setup frame.
6996 __ push(ebp);
6997 __ mov(ebp, Operand(esp));
6998
6999 // Save callee-saved registers (C calling conventions).
7000 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
7001 // Push something that is not an arguments adaptor.
7002 __ push(Immediate(~ArgumentsAdaptorFrame::SENTINEL));
7003 __ push(Immediate(Smi::FromInt(marker))); // @ function offset
7004 __ push(edi);
7005 __ push(esi);
7006 __ push(ebx);
7007
7008 // Save copies of the top frame descriptor on the stack.
7009 ExternalReference c_entry_fp(Top::k_c_entry_fp_address);
7010 __ push(Operand::StaticVariable(c_entry_fp));
7011
7012 // Call a faked try-block that does the invoke.
7013 __ call(&invoke);
7014
7015 // Caught exception: Store result (exception) in the pending
7016 // exception field in the JSEnv and return a failure sentinel.
7017 ExternalReference pending_exception(Top::k_pending_exception_address);
7018 __ mov(Operand::StaticVariable(pending_exception), eax);
7019 __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
7020 __ jmp(&exit);
7021
7022 // Invoke: Link this frame into the handler chain.
7023 __ bind(&invoke);
7024 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
7025 __ push(eax); // flush TOS
7026
7027 // Clear any pending exceptions.
7028 __ mov(edx,
7029 Operand::StaticVariable(ExternalReference::the_hole_value_location()));
7030 __ mov(Operand::StaticVariable(pending_exception), edx);
7031
7032 // Fake a receiver (NULL).
7033 __ push(Immediate(0)); // receiver
7034
7035 // Invoke the function by calling through JS entry trampoline
7036 // builtin and pop the faked function when we return. Notice that we
7037 // cannot store a reference to the trampoline code directly in this
7038 // stub, because the builtin stubs may not have been generated yet.
7039 if (is_construct) {
7040 ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
7041 __ mov(edx, Immediate(construct_entry));
7042 } else {
7043 ExternalReference entry(Builtins::JSEntryTrampoline);
7044 __ mov(edx, Immediate(entry));
7045 }
7046 __ mov(edx, Operand(edx, 0)); // deref address
7047 __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
7048 __ call(Operand(edx));
7049
7050 // Unlink this frame from the handler chain.
7051 __ pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
7052 // Pop next_sp.
7053 __ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
7054
7055 // Restore the top frame descriptor from the stack.
7056 __ bind(&exit);
7057 __ pop(Operand::StaticVariable(ExternalReference(Top::k_c_entry_fp_address)));
7058
7059 // Restore callee-saved registers (C calling conventions).
7060 __ pop(ebx);
7061 __ pop(esi);
7062 __ pop(edi);
7063 __ add(Operand(esp), Immediate(2 * kPointerSize)); // remove markers
7064
7065 // Restore frame pointer and return.
7066 __ pop(ebp);
7067 __ ret(0);
7068 }
7069
7070
7071 void InstanceofStub::Generate(MacroAssembler* masm) {
7072 // Get the object - go slow case if it's a smi.
7073 Label slow;
7074 __ mov(eax, Operand(esp, 2 * kPointerSize)); // 2 ~ return address, function
7075 __ test(eax, Immediate(kSmiTagMask));
7076 __ j(zero, &slow, not_taken);
7077
7078 // Check that the left hand is a JS object.
7079 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); // ebx - object map
7080 __ movzx_b(ecx, FieldOperand(eax, Map::kInstanceTypeOffset)); // ecx - type
7081 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
7082 __ j(less, &slow, not_taken);
7083 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
7084 __ j(greater, &slow, not_taken);
7085
7086 // Get the prototype of the function.
7087 __ mov(edx, Operand(esp, 1 * kPointerSize)); // 1 ~ return address
7088 __ TryGetFunctionPrototype(edx, ebx, ecx, &slow);
7089
7090 // Check that the function prototype is a JS object.
7091 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
7092 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
7093 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
7094 __ j(less, &slow, not_taken);
7095 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
7096 __ j(greater, &slow, not_taken);
7097
7098 // Register mapping: eax is object map and ebx is function prototype.
7099 __ mov(ecx, FieldOperand(eax, Map::kPrototypeOffset));
7100
7101 // Loop through the prototype chain looking for the function prototype.
7102 Label loop, is_instance, is_not_instance;
7103 __ bind(&loop);
7104 __ cmp(ecx, Operand(ebx));
7105 __ j(equal, &is_instance);
7106 __ cmp(Operand(ecx), Immediate(Factory::null_value()));
7107 __ j(equal, &is_not_instance);
7108 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
7109 __ mov(ecx, FieldOperand(ecx, Map::kPrototypeOffset));
7110 __ jmp(&loop);
7111
7112 __ bind(&is_instance);
7113 __ Set(eax, Immediate(0));
7114 __ ret(2 * kPointerSize);
7115
7116 __ bind(&is_not_instance);
7117 __ Set(eax, Immediate(Smi::FromInt(1)));
7118 __ ret(2 * kPointerSize);
7119
7120 // Slow-case: Go through the JavaScript implementation.
7121 __ bind(&slow);
7122 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
7123 }
7124
7125
7126 #undef __
7127
7128 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-ia32.h ('k') | src/constants-arm.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698