1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #if V8_TARGET_ARCH_X87
6
7 #include "src/full-codegen/full-codegen.h"
8 #include "src/ast/compile-time-value.h"
9 #include "src/ast/scopes.h"
10 #include "src/code-factory.h"
11 #include "src/code-stubs.h"
12 #include "src/codegen.h"
13 #include "src/compilation-info.h"
14 #include "src/compiler.h"
15 #include "src/debug/debug.h"
16 #include "src/ic/ic.h"
17 #include "src/x87/frames-x87.h"
18
19 namespace v8 {
20 namespace internal {
21
22 #define __ ACCESS_MASM(masm())
23
24 class JumpPatchSite BASE_EMBEDDED {
25 public:
JumpPatchSite(MacroAssembler * masm)26 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
27 #ifdef DEBUG
28 info_emitted_ = false;
29 #endif
30 }
31
~JumpPatchSite()32 ~JumpPatchSite() {
33 DCHECK(patch_site_.is_bound() == info_emitted_);
34 }
35
EmitJumpIfNotSmi(Register reg,Label * target,Label::Distance distance=Label::kFar)36 void EmitJumpIfNotSmi(Register reg,
37 Label* target,
38 Label::Distance distance = Label::kFar) {
39 __ test(reg, Immediate(kSmiTagMask));
40 EmitJump(not_carry, target, distance); // Always taken before patched.
41 }
42
EmitJumpIfSmi(Register reg,Label * target,Label::Distance distance=Label::kFar)43 void EmitJumpIfSmi(Register reg,
44 Label* target,
45 Label::Distance distance = Label::kFar) {
46 __ test(reg, Immediate(kSmiTagMask));
47 EmitJump(carry, target, distance); // Never taken before patched.
48 }
49
EmitPatchInfo()50 void EmitPatchInfo() {
51 if (patch_site_.is_bound()) {
52 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
53 DCHECK(is_uint8(delta_to_patch_site));
54 __ test(eax, Immediate(delta_to_patch_site));
55 #ifdef DEBUG
56 info_emitted_ = true;
57 #endif
58 } else {
59 __ nop(); // Signals no inlined code.
60 }
61 }
62
63 private:
64 // jc will be patched with jz, jnc will become jnz.
EmitJump(Condition cc,Label * target,Label::Distance distance)65 void EmitJump(Condition cc, Label* target, Label::Distance distance) {
66 DCHECK(!patch_site_.is_bound() && !info_emitted_);
67 DCHECK(cc == carry || cc == not_carry);
68 __ bind(&patch_site_);
69 __ j(cc, target, distance);
70 }
71
masm()72 MacroAssembler* masm() { return masm_; }
73 MacroAssembler* masm_;
74 Label patch_site_;
75 #ifdef DEBUG
76 bool info_emitted_;
77 #endif
78 };
79
80
81 // Generate code for a JS function. On entry to the function the receiver
82 // and arguments have been pushed on the stack left to right, with the
83 // return address on top of them. The actual argument count matches the
84 // formal parameter count expected by the function.
85 //
86 // The live registers are:
87 // o edi: the JS function object being called (i.e. ourselves)
88 // o edx: the new target value
89 // o esi: our context
90 // o ebp: our caller's frame pointer
91 // o esp: stack pointer (pointing to return address)
92 //
93 // The function builds a JS frame. Please see JavaScriptFrameConstants in
94 // frames-x87.h for its layout.
Generate()95 void FullCodeGenerator::Generate() {
96 CompilationInfo* info = info_;
97 profiling_counter_ = isolate()->factory()->NewCell(
98 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
99 SetFunctionPosition(literal());
100 Comment cmnt(masm_, "[ function compiled by full code generator");
101
102 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
103
104 if (FLAG_debug_code && info->ExpectsJSReceiverAsReceiver()) {
105 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
106 __ mov(ecx, Operand(esp, receiver_offset));
107 __ AssertNotSmi(ecx);
108 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ecx);
109 __ Assert(above_equal, kSloppyFunctionExpectsJSReceiverReceiver);
110 }
111
112 // Open a frame scope to indicate that there is a frame on the stack. The
113 // MANUAL indicates that the scope shouldn't actually generate code to set up
114 // the frame (that is done below).
115 FrameScope frame_scope(masm_, StackFrame::MANUAL);
116
117 info->set_prologue_offset(masm_->pc_offset());
118 __ Prologue(info->GeneratePreagedPrologue());
119
120 // Increment invocation count for the function.
121 {
122 Comment cmnt(masm_, "[ Increment invocation count");
123 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
124 __ mov(ecx, FieldOperand(ecx, LiteralsArray::kFeedbackVectorOffset));
125 __ add(FieldOperand(
126 ecx, TypeFeedbackVector::kInvocationCountIndex * kPointerSize +
127 TypeFeedbackVector::kHeaderSize),
128 Immediate(Smi::FromInt(1)));
129 }
130
131 { Comment cmnt(masm_, "[ Allocate locals");
132 int locals_count = info->scope()->num_stack_slots();
133 // Generators allocate locals, if any, in context slots.
134 DCHECK(!IsGeneratorFunction(literal()->kind()) || locals_count == 0);
135 OperandStackDepthIncrement(locals_count);
136 if (locals_count == 1) {
137 __ push(Immediate(isolate()->factory()->undefined_value()));
138 } else if (locals_count > 1) {
139 if (locals_count >= 128) {
140 Label ok;
141 __ mov(ecx, esp);
142 __ sub(ecx, Immediate(locals_count * kPointerSize));
143 ExternalReference stack_limit =
144 ExternalReference::address_of_real_stack_limit(isolate());
145 __ cmp(ecx, Operand::StaticVariable(stack_limit));
146 __ j(above_equal, &ok, Label::kNear);
147 __ CallRuntime(Runtime::kThrowStackOverflow);
148 __ bind(&ok);
149 }
150 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
151 const int kMaxPushes = 32;
152 if (locals_count >= kMaxPushes) {
153 int loop_iterations = locals_count / kMaxPushes;
154 __ mov(ecx, loop_iterations);
155 Label loop_header;
156 __ bind(&loop_header);
157 // Do pushes.
158 for (int i = 0; i < kMaxPushes; i++) {
159 __ push(eax);
160 }
161 __ dec(ecx);
162 __ j(not_zero, &loop_header, Label::kNear);
163 }
164 int remaining = locals_count % kMaxPushes;
165 // Emit the remaining pushes.
166 for (int i = 0; i < remaining; i++) {
167 __ push(eax);
168 }
169 }
170 }
171
172 bool function_in_register = true;
173
174 // Possibly allocate a local context.
175 if (info->scope()->NeedsContext()) {
176 Comment cmnt(masm_, "[ Allocate context");
177 bool need_write_barrier = true;
178 int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
179 // Argument to NewContext is the function, which is still in edi.
180 if (info->scope()->is_script_scope()) {
181 __ push(edi);
182 __ Push(info->scope()->scope_info());
183 __ CallRuntime(Runtime::kNewScriptContext);
184 PrepareForBailoutForId(BailoutId::ScriptContext(),
185 BailoutState::TOS_REGISTER);
186 // The new target value is not used, clobbering is safe.
187 DCHECK_NULL(info->scope()->new_target_var());
188 } else {
189 if (info->scope()->new_target_var() != nullptr) {
190 __ push(edx); // Preserve new target.
191 }
192 if (slots <= FastNewFunctionContextStub::kMaximumSlots) {
193 FastNewFunctionContextStub stub(isolate());
194 __ mov(FastNewFunctionContextDescriptor::SlotsRegister(),
195 Immediate(slots));
196 __ CallStub(&stub);
197 // Result of FastNewFunctionContextStub is always in new space.
198 need_write_barrier = false;
199 } else {
200 __ push(edi);
201 __ CallRuntime(Runtime::kNewFunctionContext);
202 }
203 if (info->scope()->new_target_var() != nullptr) {
204 __ pop(edx); // Restore new target.
205 }
206 }
207 function_in_register = false;
208 // Context is returned in eax. It replaces the context passed to us.
209 // It's saved in the stack and kept live in esi.
210 __ mov(esi, eax);
211 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax);
212
213 // Copy parameters into context if necessary.
214 int num_parameters = info->scope()->num_parameters();
215 int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
216 for (int i = first_parameter; i < num_parameters; i++) {
217 Variable* var =
218 (i == -1) ? info->scope()->receiver() : info->scope()->parameter(i);
219 if (var->IsContextSlot()) {
220 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
221 (num_parameters - 1 - i) * kPointerSize;
222 // Load parameter from stack.
223 __ mov(eax, Operand(ebp, parameter_offset));
224 // Store it in the context.
225 int context_offset = Context::SlotOffset(var->index());
226 __ mov(Operand(esi, context_offset), eax);
227 // Update the write barrier. This clobbers eax and ebx.
228 if (need_write_barrier) {
229 __ RecordWriteContextSlot(esi, context_offset, eax, ebx,
230 kDontSaveFPRegs);
231 } else if (FLAG_debug_code) {
232 Label done;
233 __ JumpIfInNewSpace(esi, eax, &done, Label::kNear);
234 __ Abort(kExpectedNewSpaceObject);
235 __ bind(&done);
236 }
237 }
238 }
239 }
240
241 // Register holding this function and new target are both trashed in case we
242 // bailout here. But since that can happen only when new target is not used
243 // and we allocate a context, the value of |function_in_register| is correct.
244 PrepareForBailoutForId(BailoutId::FunctionContext(),
245 BailoutState::NO_REGISTERS);
246
247 // Possibly set up a local binding to the this function which is used in
248 // derived constructors with super calls.
249 Variable* this_function_var = info->scope()->this_function_var();
250 if (this_function_var != nullptr) {
251 Comment cmnt(masm_, "[ This function");
252 if (!function_in_register) {
253 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
254 // The write barrier clobbers register again, keep it marked as such.
255 }
256 SetVar(this_function_var, edi, ebx, ecx);
257 }
258
259 // Possibly set up a local binding to the new target value.
260 Variable* new_target_var = info->scope()->new_target_var();
261 if (new_target_var != nullptr) {
262 Comment cmnt(masm_, "[ new.target");
263 SetVar(new_target_var, edx, ebx, ecx);
264 }
265
266 // Possibly allocate RestParameters
267 Variable* rest_param = info->scope()->rest_parameter();
268 if (rest_param != nullptr) {
269 Comment cmnt(masm_, "[ Allocate rest parameter array");
270 if (!function_in_register) {
271 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
272 }
273 FastNewRestParameterStub stub(isolate());
274 __ CallStub(&stub);
275 function_in_register = false;
276 SetVar(rest_param, eax, ebx, edx);
277 }
278
279 Variable* arguments = info->scope()->arguments();
280 if (arguments != NULL) {
281 // Arguments object must be allocated after the context object, in
282 // case the "arguments" or ".arguments" variables are in the context.
283 Comment cmnt(masm_, "[ Allocate arguments object");
284 if (!function_in_register) {
285 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
286 }
287 if (is_strict(language_mode()) || !has_simple_parameters()) {
288 FastNewStrictArgumentsStub stub(isolate());
289 __ CallStub(&stub);
290 } else if (literal()->has_duplicate_parameters()) {
291 __ Push(edi);
292 __ CallRuntime(Runtime::kNewSloppyArguments_Generic);
293 } else {
294 FastNewSloppyArgumentsStub stub(isolate());
295 __ CallStub(&stub);
296 }
297
298 SetVar(arguments, eax, ebx, edx);
299 }
300
301 if (FLAG_trace) {
302 __ CallRuntime(Runtime::kTraceEnter);
303 }
304
305 // Visit the declarations and body.
306 PrepareForBailoutForId(BailoutId::FunctionEntry(),
307 BailoutState::NO_REGISTERS);
308 {
309 Comment cmnt(masm_, "[ Declarations");
310 VisitDeclarations(scope()->declarations());
311 }
312
313 // Assert that the declarations do not use ICs. Otherwise the debugger
314 // won't be able to redirect a PC at an IC to the correct IC in newly
315 // recompiled code.
316 DCHECK_EQ(0, ic_total_count_);
317
318 {
319 Comment cmnt(masm_, "[ Stack check");
320 PrepareForBailoutForId(BailoutId::Declarations(),
321 BailoutState::NO_REGISTERS);
322 Label ok;
323 ExternalReference stack_limit =
324 ExternalReference::address_of_stack_limit(isolate());
325 __ cmp(esp, Operand::StaticVariable(stack_limit));
326 __ j(above_equal, &ok, Label::kNear);
327 __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
328 __ bind(&ok);
329 }
330
331 {
332 Comment cmnt(masm_, "[ Body");
333 DCHECK(loop_depth() == 0);
334 VisitStatements(literal()->body());
335 DCHECK(loop_depth() == 0);
336 }
337
338 // Always emit a 'return undefined' in case control fell off the end of
339 // the body.
340 { Comment cmnt(masm_, "[ return <undefined>;");
341 __ mov(eax, isolate()->factory()->undefined_value());
342 EmitReturnSequence();
343 }
344 }
345
346
ClearAccumulator()347 void FullCodeGenerator::ClearAccumulator() {
348 __ Move(eax, Immediate(Smi::kZero));
349 }
350
351
EmitProfilingCounterDecrement(int delta)352 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
353 __ mov(ebx, Immediate(profiling_counter_));
354 __ sub(FieldOperand(ebx, Cell::kValueOffset),
355 Immediate(Smi::FromInt(delta)));
356 }
357
358
EmitProfilingCounterReset()359 void FullCodeGenerator::EmitProfilingCounterReset() {
360 int reset_value = FLAG_interrupt_budget;
361 __ mov(ebx, Immediate(profiling_counter_));
362 __ mov(FieldOperand(ebx, Cell::kValueOffset),
363 Immediate(Smi::FromInt(reset_value)));
364 }
365
366
EmitBackEdgeBookkeeping(IterationStatement * stmt,Label * back_edge_target)367 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
368 Label* back_edge_target) {
369 Comment cmnt(masm_, "[ Back edge bookkeeping");
370 Label ok;
371
372 DCHECK(back_edge_target->is_bound());
373 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
374 int weight = Min(kMaxBackEdgeWeight,
375 Max(1, distance / kCodeSizeMultiplier));
376 EmitProfilingCounterDecrement(weight);
377 __ j(positive, &ok, Label::kNear);
378 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
379
380 // Record a mapping of this PC offset to the OSR id. This is used to find
381 // the AST id from the unoptimized code in order to use it as a key into
382 // the deoptimization input data found in the optimized code.
383 RecordBackEdge(stmt->OsrEntryId());
384
385 EmitProfilingCounterReset();
386
387 __ bind(&ok);
388 PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
389 // Record a mapping of the OSR id to this PC. This is used if the OSR
390 // entry becomes the target of a bailout. We don't expect it to be, but
391 // we want it to work if it is.
392 PrepareForBailoutForId(stmt->OsrEntryId(), BailoutState::NO_REGISTERS);
393 }
394
EmitProfilingCounterHandlingForReturnSequence(bool is_tail_call)395 void FullCodeGenerator::EmitProfilingCounterHandlingForReturnSequence(
396 bool is_tail_call) {
397 // Pretend that the exit is a backwards jump to the entry.
398 int weight = 1;
399 if (info_->ShouldSelfOptimize()) {
400 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
401 } else {
402 int distance = masm_->pc_offset();
403 weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier));
404 }
405 EmitProfilingCounterDecrement(weight);
406 Label ok;
407 __ j(positive, &ok, Label::kNear);
408 // Don't need to save result register if we are going to do a tail call.
409 if (!is_tail_call) {
410 __ push(eax);
411 }
412 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
413 if (!is_tail_call) {
414 __ pop(eax);
415 }
416 EmitProfilingCounterReset();
417 __ bind(&ok);
418 }
419
EmitReturnSequence()420 void FullCodeGenerator::EmitReturnSequence() {
421 Comment cmnt(masm_, "[ Return sequence");
422 if (return_label_.is_bound()) {
423 __ jmp(&return_label_);
424 } else {
425 // Common return label
426 __ bind(&return_label_);
427 if (FLAG_trace) {
428 __ push(eax);
429 __ CallRuntime(Runtime::kTraceExit);
430 }
431 EmitProfilingCounterHandlingForReturnSequence(false);
432
433 SetReturnPosition(literal());
434 __ leave();
435
436 int arg_count = info_->scope()->num_parameters() + 1;
437 int arguments_bytes = arg_count * kPointerSize;
438 __ Ret(arguments_bytes, ecx);
439 }
440 }
441
RestoreContext()442 void FullCodeGenerator::RestoreContext() {
443 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
444 }
445
Plug(Variable * var) const446 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
447 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
448 MemOperand operand = codegen()->VarOperand(var, result_register());
449 // Memory operands can be pushed directly.
450 codegen()->PushOperand(operand);
451 }
452
453
Plug(Heap::RootListIndex index) const454 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
455 UNREACHABLE(); // Not used on X87.
456 }
457
458
Plug(Heap::RootListIndex index) const459 void FullCodeGenerator::AccumulatorValueContext::Plug(
460 Heap::RootListIndex index) const {
461 UNREACHABLE(); // Not used on X87.
462 }
463
464
Plug(Heap::RootListIndex index) const465 void FullCodeGenerator::StackValueContext::Plug(
466 Heap::RootListIndex index) const {
467 UNREACHABLE(); // Not used on X87.
468 }
469
470
Plug(Heap::RootListIndex index) const471 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
472 UNREACHABLE(); // Not used on X87.
473 }
474
475
Plug(Handle<Object> lit) const476 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
477 }
478
479
Plug(Handle<Object> lit) const480 void FullCodeGenerator::AccumulatorValueContext::Plug(
481 Handle<Object> lit) const {
482 if (lit->IsSmi()) {
483 __ SafeMove(result_register(), Immediate(lit));
484 } else {
485 __ Move(result_register(), Immediate(lit));
486 }
487 }
488
489
Plug(Handle<Object> lit) const490 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
491 codegen()->OperandStackDepthIncrement(1);
492 if (lit->IsSmi()) {
493 __ SafePush(Immediate(lit));
494 } else {
495 __ push(Immediate(lit));
496 }
497 }
498
499
Plug(Handle<Object> lit) const500 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
501 codegen()->PrepareForBailoutBeforeSplit(condition(),
502 true,
503 true_label_,
504 false_label_);
505 DCHECK(lit->IsNull(isolate()) || lit->IsUndefined(isolate()) ||
506 !lit->IsUndetectable());
507 if (lit->IsUndefined(isolate()) || lit->IsNull(isolate()) ||
508 lit->IsFalse(isolate())) {
509 if (false_label_ != fall_through_) __ jmp(false_label_);
510 } else if (lit->IsTrue(isolate()) || lit->IsJSObject()) {
511 if (true_label_ != fall_through_) __ jmp(true_label_);
512 } else if (lit->IsString()) {
513 if (String::cast(*lit)->length() == 0) {
514 if (false_label_ != fall_through_) __ jmp(false_label_);
515 } else {
516 if (true_label_ != fall_through_) __ jmp(true_label_);
517 }
518 } else if (lit->IsSmi()) {
519 if (Smi::cast(*lit)->value() == 0) {
520 if (false_label_ != fall_through_) __ jmp(false_label_);
521 } else {
522 if (true_label_ != fall_through_) __ jmp(true_label_);
523 }
524 } else {
525 // For simplicity we always test the accumulator register.
526 __ mov(result_register(), lit);
527 codegen()->DoTest(this);
528 }
529 }
530
531
DropAndPlug(int count,Register reg) const532 void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
533 Register reg) const {
534 DCHECK(count > 0);
535 if (count > 1) codegen()->DropOperands(count - 1);
536 __ mov(Operand(esp, 0), reg);
537 }
538
539
Plug(Label * materialize_true,Label * materialize_false) const540 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
541 Label* materialize_false) const {
542 DCHECK(materialize_true == materialize_false);
543 __ bind(materialize_true);
544 }
545
546
Plug(Label * materialize_true,Label * materialize_false) const547 void FullCodeGenerator::AccumulatorValueContext::Plug(
548 Label* materialize_true,
549 Label* materialize_false) const {
550 Label done;
551 __ bind(materialize_true);
552 __ mov(result_register(), isolate()->factory()->true_value());
553 __ jmp(&done, Label::kNear);
554 __ bind(materialize_false);
555 __ mov(result_register(), isolate()->factory()->false_value());
556 __ bind(&done);
557 }
558
559
Plug(Label * materialize_true,Label * materialize_false) const560 void FullCodeGenerator::StackValueContext::Plug(
561 Label* materialize_true,
562 Label* materialize_false) const {
563 codegen()->OperandStackDepthIncrement(1);
564 Label done;
565 __ bind(materialize_true);
566 __ push(Immediate(isolate()->factory()->true_value()));
567 __ jmp(&done, Label::kNear);
568 __ bind(materialize_false);
569 __ push(Immediate(isolate()->factory()->false_value()));
570 __ bind(&done);
571 }
572
573
Plug(Label * materialize_true,Label * materialize_false) const574 void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
575 Label* materialize_false) const {
576 DCHECK(materialize_true == true_label_);
577 DCHECK(materialize_false == false_label_);
578 }
579
580
Plug(bool flag) const581 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
582 Handle<Object> value = flag
583 ? isolate()->factory()->true_value()
584 : isolate()->factory()->false_value();
585 __ mov(result_register(), value);
586 }
587
588
Plug(bool flag) const589 void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
590 codegen()->OperandStackDepthIncrement(1);
591 Handle<Object> value = flag
592 ? isolate()->factory()->true_value()
593 : isolate()->factory()->false_value();
594 __ push(Immediate(value));
595 }
596
597
Plug(bool flag) const598 void FullCodeGenerator::TestContext::Plug(bool flag) const {
599 codegen()->PrepareForBailoutBeforeSplit(condition(),
600 true,
601 true_label_,
602 false_label_);
603 if (flag) {
604 if (true_label_ != fall_through_) __ jmp(true_label_);
605 } else {
606 if (false_label_ != fall_through_) __ jmp(false_label_);
607 }
608 }
609
610
DoTest(Expression * condition,Label * if_true,Label * if_false,Label * fall_through)611 void FullCodeGenerator::DoTest(Expression* condition,
612 Label* if_true,
613 Label* if_false,
614 Label* fall_through) {
615 Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
616 CallIC(ic, condition->test_id());
617 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
618 Split(equal, if_true, if_false, fall_through);
619 }
620
621
Split(Condition cc,Label * if_true,Label * if_false,Label * fall_through)622 void FullCodeGenerator::Split(Condition cc,
623 Label* if_true,
624 Label* if_false,
625 Label* fall_through) {
626 if (if_false == fall_through) {
627 __ j(cc, if_true);
628 } else if (if_true == fall_through) {
629 __ j(NegateCondition(cc), if_false);
630 } else {
631 __ j(cc, if_true);
632 __ jmp(if_false);
633 }
634 }
635
636
StackOperand(Variable * var)637 MemOperand FullCodeGenerator::StackOperand(Variable* var) {
638 DCHECK(var->IsStackAllocated());
639 // Offset is negative because higher indexes are at lower addresses.
640 int offset = -var->index() * kPointerSize;
641 // Adjust by a (parameter or local) base offset.
642 if (var->IsParameter()) {
643 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
644 } else {
645 offset += JavaScriptFrameConstants::kLocal0Offset;
646 }
647 return Operand(ebp, offset);
648 }
649
650
VarOperand(Variable * var,Register scratch)651 MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
652 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
653 if (var->IsContextSlot()) {
654 int context_chain_length = scope()->ContextChainLength(var->scope());
655 __ LoadContext(scratch, context_chain_length);
656 return ContextOperand(scratch, var->index());
657 } else {
658 return StackOperand(var);
659 }
660 }
661
662
GetVar(Register dest,Variable * var)663 void FullCodeGenerator::GetVar(Register dest, Variable* var) {
664 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
665 MemOperand location = VarOperand(var, dest);
666 __ mov(dest, location);
667 }
668
669
SetVar(Variable * var,Register src,Register scratch0,Register scratch1)670 void FullCodeGenerator::SetVar(Variable* var,
671 Register src,
672 Register scratch0,
673 Register scratch1) {
674 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
675 DCHECK(!scratch0.is(src));
676 DCHECK(!scratch0.is(scratch1));
677 DCHECK(!scratch1.is(src));
678 MemOperand location = VarOperand(var, scratch0);
679 __ mov(location, src);
680
681 // Emit the write barrier code if the location is in the heap.
682 if (var->IsContextSlot()) {
683 int offset = Context::SlotOffset(var->index());
684 DCHECK(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
685 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
686 }
687 }
688
689
PrepareForBailoutBeforeSplit(Expression * expr,bool should_normalize,Label * if_true,Label * if_false)690 void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
691 bool should_normalize,
692 Label* if_true,
693 Label* if_false) {
694 // Only prepare for bailouts before splits if we're in a test
695 // context. Otherwise, we let the Visit function deal with the
696 // preparation to avoid preparing with the same AST id twice.
697 if (!context()->IsTest()) return;
698
699 Label skip;
700 if (should_normalize) __ jmp(&skip, Label::kNear);
701 PrepareForBailout(expr, BailoutState::TOS_REGISTER);
702 if (should_normalize) {
703 __ cmp(eax, isolate()->factory()->true_value());
704 Split(equal, if_true, if_false, NULL);
705 __ bind(&skip);
706 }
707 }
708
709
EmitDebugCheckDeclarationContext(Variable * variable)710 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
711 // The variable in the declaration always resides in the current context.
712 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
713 if (FLAG_debug_code) {
714 // Check that we're not inside a with or catch context.
715 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
716 __ cmp(ebx, isolate()->factory()->with_context_map());
717 __ Check(not_equal, kDeclarationInWithContext);
718 __ cmp(ebx, isolate()->factory()->catch_context_map());
719 __ Check(not_equal, kDeclarationInCatchContext);
720 }
721 }
722
723
VisitVariableDeclaration(VariableDeclaration * declaration)724 void FullCodeGenerator::VisitVariableDeclaration(
725 VariableDeclaration* declaration) {
726 VariableProxy* proxy = declaration->proxy();
727 Variable* variable = proxy->var();
728 switch (variable->location()) {
729 case VariableLocation::UNALLOCATED: {
730 DCHECK(!variable->binding_needs_init());
731 FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
732 DCHECK(!slot.IsInvalid());
733 globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
734 globals_->Add(isolate()->factory()->undefined_value(), zone());
735 break;
736 }
737 case VariableLocation::PARAMETER:
738 case VariableLocation::LOCAL:
739 if (variable->binding_needs_init()) {
740 Comment cmnt(masm_, "[ VariableDeclaration");
741 __ mov(StackOperand(variable),
742 Immediate(isolate()->factory()->the_hole_value()));
743 }
744 break;
745
746 case VariableLocation::CONTEXT:
747 if (variable->binding_needs_init()) {
748 Comment cmnt(masm_, "[ VariableDeclaration");
749 EmitDebugCheckDeclarationContext(variable);
750 __ mov(ContextOperand(esi, variable->index()),
751 Immediate(isolate()->factory()->the_hole_value()));
752 // No write barrier since the hole value is in old space.
753 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
754 }
755 break;
756
757 case VariableLocation::LOOKUP: {
758 Comment cmnt(masm_, "[ VariableDeclaration");
759 DCHECK_EQ(VAR, variable->mode());
760 DCHECK(!variable->binding_needs_init());
761 __ push(Immediate(variable->name()));
762 __ CallRuntime(Runtime::kDeclareEvalVar);
763 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
764 break;
765 }
766
767 case VariableLocation::MODULE:
768 UNREACHABLE();
769 }
770 }
771
VisitFunctionDeclaration(FunctionDeclaration * declaration)772 void FullCodeGenerator::VisitFunctionDeclaration(
773 FunctionDeclaration* declaration) {
774 VariableProxy* proxy = declaration->proxy();
775 Variable* variable = proxy->var();
776 switch (variable->location()) {
777 case VariableLocation::UNALLOCATED: {
778 FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
779 DCHECK(!slot.IsInvalid());
780 globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
781 Handle<SharedFunctionInfo> function =
782 Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
783 // Check for stack-overflow exception.
784 if (function.is_null()) return SetStackOverflow();
785 globals_->Add(function, zone());
786 break;
787 }
788
789 case VariableLocation::PARAMETER:
790 case VariableLocation::LOCAL: {
791 Comment cmnt(masm_, "[ FunctionDeclaration");
792 VisitForAccumulatorValue(declaration->fun());
793 __ mov(StackOperand(variable), result_register());
794 break;
795 }
796
797 case VariableLocation::CONTEXT: {
798 Comment cmnt(masm_, "[ FunctionDeclaration");
799 EmitDebugCheckDeclarationContext(variable);
800 VisitForAccumulatorValue(declaration->fun());
801 __ mov(ContextOperand(esi, variable->index()), result_register());
802 // We know that we have written a function, which is not a smi.
803 __ RecordWriteContextSlot(esi, Context::SlotOffset(variable->index()),
804 result_register(), ecx, kDontSaveFPRegs,
805 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
806 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
807 break;
808 }
809
810 case VariableLocation::LOOKUP: {
811 Comment cmnt(masm_, "[ FunctionDeclaration");
812 PushOperand(variable->name());
813 VisitForStackValue(declaration->fun());
814 CallRuntimeWithOperands(Runtime::kDeclareEvalFunction);
815 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
816 break;
817 }
818
819 case VariableLocation::MODULE:
820 UNREACHABLE();
821 }
822 }
823
824
DeclareGlobals(Handle<FixedArray> pairs)825 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
826 // Call the runtime to declare the globals.
827 __ Push(pairs);
828 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
829 __ EmitLoadTypeFeedbackVector(eax);
830 __ Push(eax);
831 __ CallRuntime(Runtime::kDeclareGlobals);
832 // Return value is ignored.
833 }
834
835
VisitSwitchStatement(SwitchStatement * stmt)836 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
837 Comment cmnt(masm_, "[ SwitchStatement");
838 Breakable nested_statement(this, stmt);
839 SetStatementPosition(stmt);
840
841 // Keep the switch value on the stack until a case matches.
842 VisitForStackValue(stmt->tag());
843 PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
844
845 ZoneList<CaseClause*>* clauses = stmt->cases();
846 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
847
848 Label next_test; // Recycled for each test.
849 // Compile all the tests with branches to their bodies.
850 for (int i = 0; i < clauses->length(); i++) {
851 CaseClause* clause = clauses->at(i);
852 clause->body_target()->Unuse();
853
854 // The default is not a test, but remember it as final fall through.
855 if (clause->is_default()) {
856 default_clause = clause;
857 continue;
858 }
859
860 Comment cmnt(masm_, "[ Case comparison");
861 __ bind(&next_test);
862 next_test.Unuse();
863
864 // Compile the label expression.
865 VisitForAccumulatorValue(clause->label());
866
867 // Perform the comparison as if via '==='.
868 __ mov(edx, Operand(esp, 0)); // Switch value.
869 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
870 JumpPatchSite patch_site(masm_);
871 if (inline_smi_code) {
872 Label slow_case;
873 __ mov(ecx, edx);
874 __ or_(ecx, eax);
875 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
876
877 __ cmp(edx, eax);
878 __ j(not_equal, &next_test);
879 __ Drop(1); // Switch value is no longer needed.
880 __ jmp(clause->body_target());
881 __ bind(&slow_case);
882 }
883
884 SetExpressionPosition(clause);
885 Handle<Code> ic =
886 CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
887 CallIC(ic, clause->CompareId());
888 patch_site.EmitPatchInfo();
889
890 Label skip;
891 __ jmp(&skip, Label::kNear);
892 PrepareForBailout(clause, BailoutState::TOS_REGISTER);
893 __ cmp(eax, isolate()->factory()->true_value());
894 __ j(not_equal, &next_test);
895 __ Drop(1);
896 __ jmp(clause->body_target());
897 __ bind(&skip);
898
899 __ test(eax, eax);
900 __ j(not_equal, &next_test);
901 __ Drop(1); // Switch value is no longer needed.
902 __ jmp(clause->body_target());
903 }
904
905 // Discard the test value and jump to the default if present, otherwise to
906 // the end of the statement.
907 __ bind(&next_test);
908 DropOperands(1); // Switch value is no longer needed.
909 if (default_clause == NULL) {
910 __ jmp(nested_statement.break_label());
911 } else {
912 __ jmp(default_clause->body_target());
913 }
914
915 // Compile all the case bodies.
916 for (int i = 0; i < clauses->length(); i++) {
917 Comment cmnt(masm_, "[ Case body");
918 CaseClause* clause = clauses->at(i);
919 __ bind(clause->body_target());
920 PrepareForBailoutForId(clause->EntryId(), BailoutState::NO_REGISTERS);
921 VisitStatements(clause->statements());
922 }
923
924 __ bind(nested_statement.break_label());
925 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
926 }
927
928
VisitForInStatement(ForInStatement * stmt)929 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
930 Comment cmnt(masm_, "[ ForInStatement");
931 SetStatementPosition(stmt, SKIP_BREAK);
932
933 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
934
935 // Get the object to enumerate over.
936 SetExpressionAsStatementPosition(stmt->enumerable());
937 VisitForAccumulatorValue(stmt->enumerable());
938 OperandStackDepthIncrement(5);
939
940 Label loop, exit;
941 Iteration loop_statement(this, stmt);
942 increment_loop_depth();
943
944 // If the object is null or undefined, skip over the loop, otherwise convert
945 // it to a JS receiver. See ECMA-262 version 5, section 12.6.4.
946 Label convert, done_convert;
947 __ JumpIfSmi(eax, &convert, Label::kNear);
948 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
949 __ j(above_equal, &done_convert, Label::kNear);
950 __ cmp(eax, isolate()->factory()->undefined_value());
951 __ j(equal, &exit);
952 __ cmp(eax, isolate()->factory()->null_value());
953 __ j(equal, &exit);
954 __ bind(&convert);
955 __ Call(isolate()->builtins()->ToObject(), RelocInfo::CODE_TARGET);
956 RestoreContext();
957 __ bind(&done_convert);
958 PrepareForBailoutForId(stmt->ToObjectId(), BailoutState::TOS_REGISTER);
959 __ push(eax);
960
961 // Check cache validity in generated code. If we cannot guarantee cache
962 // validity, call the runtime system to check cache validity or get the
963 // property names in a fixed array. Note: Proxies never have an enum cache,
964 // so will always take the slow path.
965 Label call_runtime, use_cache, fixed_array;
966 __ CheckEnumCache(&call_runtime);
967
968 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
969 __ jmp(&use_cache, Label::kNear);
970
971 // Get the set of properties to enumerate.
972 __ bind(&call_runtime);
973 __ push(eax);
974 __ CallRuntime(Runtime::kForInEnumerate);
975 PrepareForBailoutForId(stmt->EnumId(), BailoutState::TOS_REGISTER);
976 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
977 isolate()->factory()->meta_map());
978 __ j(not_equal, &fixed_array);
979
980
981 // We got a map in register eax. Get the enumeration cache from it.
982 Label no_descriptors;
983 __ bind(&use_cache);
984
985 __ EnumLength(edx, eax);
986 __ cmp(edx, Immediate(Smi::kZero));
987 __ j(equal, &no_descriptors);
988
989 __ LoadInstanceDescriptors(eax, ecx);
990 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheOffset));
991 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
992
993 // Set up the four remaining stack slots.
994 __ push(eax); // Map.
995 __ push(ecx); // Enumeration cache.
996 __ push(edx); // Number of valid entries for the map in the enum cache.
997 __ push(Immediate(Smi::kZero)); // Initial index.
998 __ jmp(&loop);
999
1000 __ bind(&no_descriptors);
1001 __ add(esp, Immediate(kPointerSize));
1002 __ jmp(&exit);
1003
1004 // We got a fixed array in register eax. Iterate through that.
1005 __ bind(&fixed_array);
1006
1007 __ push(Immediate(Smi::FromInt(1))); // Smi(1) indicates slow check
1008 __ push(eax); // Array
1009 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
1010 __ push(eax); // Fixed array length (as smi).
1011 PrepareForBailoutForId(stmt->PrepareId(), BailoutState::NO_REGISTERS);
1012 __ push(Immediate(Smi::kZero)); // Initial index.
1013
1014 // Generate code for doing the condition check.
1015 __ bind(&loop);
1016 SetExpressionAsStatementPosition(stmt->each());
1017
1018 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
1019 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
1020 __ j(above_equal, loop_statement.break_label());
1021
1022 // Get the current entry of the array into register eax.
1023 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1024 __ mov(eax, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1025
1026 // Get the expected map from the stack or a smi in the
1027 // permanent slow case into register edx.
1028 __ mov(edx, Operand(esp, 3 * kPointerSize));
1029
1030 // Check if the expected map still matches that of the enumerable.
1031 // If not, we may have to filter the key.
1032 Label update_each;
1033 __ mov(ebx, Operand(esp, 4 * kPointerSize));
1034 __ cmp(edx, FieldOperand(ebx, HeapObject::kMapOffset));
1035 __ j(equal, &update_each, Label::kNear);
1036
1037 // We need to filter the key, record slow-path here.
1038 int const vector_index = SmiFromSlot(slot)->value();
1039 __ EmitLoadTypeFeedbackVector(edx);
1040 __ mov(FieldOperand(edx, FixedArray::OffsetOfElementAt(vector_index)),
1041 Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate())));
1042
1043 // eax contains the key. The receiver in ebx is the second argument to the
1044 // ForInFilter. ForInFilter returns undefined if the receiver doesn't
1045 // have the key or returns the name-converted key.
1046 __ Call(isolate()->builtins()->ForInFilter(), RelocInfo::CODE_TARGET);
1047 RestoreContext();
1048 PrepareForBailoutForId(stmt->FilterId(), BailoutState::TOS_REGISTER);
1049 __ JumpIfRoot(result_register(), Heap::kUndefinedValueRootIndex,
1050 loop_statement.continue_label());
1051
1052 // Update the 'each' property or variable from the possibly filtered
1053 // entry in register eax.
1054 __ bind(&update_each);
1055 // Perform the assignment as if via '='.
1056 { EffectContext context(this);
1057 EmitAssignment(stmt->each(), stmt->EachFeedbackSlot());
1058 PrepareForBailoutForId(stmt->AssignmentId(), BailoutState::NO_REGISTERS);
1059 }
1060
1061 // Both Crankshaft and Turbofan expect BodyId to be right before stmt->body().
1062 PrepareForBailoutForId(stmt->BodyId(), BailoutState::NO_REGISTERS);
1063 // Generate code for the body of the loop.
1064 Visit(stmt->body());
1065
1066 // Generate code for going to the next element by incrementing the
1067 // index (smi) stored on top of the stack.
1068 __ bind(loop_statement.continue_label());
1069 PrepareForBailoutForId(stmt->IncrementId(), BailoutState::NO_REGISTERS);
1070 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
1071
1072 EmitBackEdgeBookkeeping(stmt, &loop);
1073 __ jmp(&loop);
1074
1075 // Remove the pointers stored on the stack.
1076 __ bind(loop_statement.break_label());
1077 DropOperands(5);
1078
1079 // Exit and decrement the loop depth.
1080 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
1081 __ bind(&exit);
1082 decrement_loop_depth();
1083 }
1084
1085
EmitSetHomeObject(Expression * initializer,int offset,FeedbackVectorSlot slot)1086 void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset,
1087 FeedbackVectorSlot slot) {
1088 DCHECK(NeedsHomeObject(initializer));
1089 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1090 __ mov(StoreDescriptor::ValueRegister(), Operand(esp, offset * kPointerSize));
1091 CallStoreIC(slot, isolate()->factory()->home_object_symbol());
1092 }
1093
1094
EmitSetHomeObjectAccumulator(Expression * initializer,int offset,FeedbackVectorSlot slot)1095 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer,
1096 int offset,
1097 FeedbackVectorSlot slot) {
1098 DCHECK(NeedsHomeObject(initializer));
1099 __ mov(StoreDescriptor::ReceiverRegister(), eax);
1100 __ mov(StoreDescriptor::ValueRegister(), Operand(esp, offset * kPointerSize));
1101 CallStoreIC(slot, isolate()->factory()->home_object_symbol());
1102 }
1103
1104
EmitLoadGlobalCheckExtensions(VariableProxy * proxy,TypeofMode typeof_mode,Label * slow)1105 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
1106 TypeofMode typeof_mode,
1107 Label* slow) {
1108 Register context = esi;
1109 Register temp = edx;
1110
1111 int to_check = scope()->ContextChainLengthUntilOutermostSloppyEval();
1112 for (Scope* s = scope(); to_check > 0; s = s->outer_scope()) {
1113 if (!s->NeedsContext()) continue;
1114 if (s->calls_sloppy_eval()) {
1115 // Check that extension is "the hole".
1116 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1117 Heap::kTheHoleValueRootIndex, slow);
1118 }
1119 // Load next context in chain.
1120 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1121 // Walk the rest of the chain without clobbering esi.
1122 context = temp;
1123 to_check--;
1124 }
1125
1126 // All extension objects were empty and it is safe to use a normal global
1127 // load machinery.
1128 EmitGlobalVariableLoad(proxy, typeof_mode);
1129 }
1130
1131
ContextSlotOperandCheckExtensions(Variable * var,Label * slow)1132 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1133 Label* slow) {
1134 DCHECK(var->IsContextSlot());
1135 Register context = esi;
1136 Register temp = ebx;
1137
1138 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
1139 if (s->NeedsContext()) {
1140 if (s->calls_sloppy_eval()) {
1141 // Check that extension is "the hole".
1142 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1143 Heap::kTheHoleValueRootIndex, slow);
1144 }
1145 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1146 // Walk the rest of the chain without clobbering esi.
1147 context = temp;
1148 }
1149 }
1150 // Check that last extension is "the hole".
1151 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1152 Heap::kTheHoleValueRootIndex, slow);
1153
1154 // This function is used only for loads, not stores, so it's safe to
1155 // return an esi-based operand (the write barrier cannot be allowed to
1156 // destroy the esi register).
1157 return ContextOperand(context, var->index());
1158 }
1159
1160
EmitDynamicLookupFastCase(VariableProxy * proxy,TypeofMode typeof_mode,Label * slow,Label * done)1161 void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
1162 TypeofMode typeof_mode,
1163 Label* slow, Label* done) {
1164 // Generate fast-case code for variables that might be shadowed by
1165 // eval-introduced variables. Eval is used a lot without
1166 // introducing variables. In those cases, we do not want to
1167 // perform a runtime call for all variables in the scope
1168 // containing the eval.
1169 Variable* var = proxy->var();
1170 if (var->mode() == DYNAMIC_GLOBAL) {
1171 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow);
1172 __ jmp(done);
1173 } else if (var->mode() == DYNAMIC_LOCAL) {
1174 Variable* local = var->local_if_not_shadowed();
1175 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
1176 if (local->binding_needs_init()) {
1177 __ cmp(eax, isolate()->factory()->the_hole_value());
1178 __ j(not_equal, done);
1179 __ push(Immediate(var->name()));
1180 __ CallRuntime(Runtime::kThrowReferenceError);
1181 } else {
1182 __ jmp(done);
1183 }
1184 }
1185 }
1186
EmitVariableLoad(VariableProxy * proxy,TypeofMode typeof_mode)1187 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
1188 TypeofMode typeof_mode) {
1189 SetExpressionPosition(proxy);
1190 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS);
1191 Variable* var = proxy->var();
1192
1193 // Three cases: global variables, lookup variables, and all other types of
1194 // variables.
1195 switch (var->location()) {
1196 case VariableLocation::UNALLOCATED: {
1197 Comment cmnt(masm_, "[ Global variable");
1198 EmitGlobalVariableLoad(proxy, typeof_mode);
1199 context()->Plug(eax);
1200 break;
1201 }
1202
1203 case VariableLocation::PARAMETER:
1204 case VariableLocation::LOCAL:
1205 case VariableLocation::CONTEXT: {
1206 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
1207 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
1208 : "[ Stack variable");
1209
1210 if (proxy->hole_check_mode() == HoleCheckMode::kRequired) {
1211 // Throw a reference error when using an uninitialized let/const
1212 // binding in harmony mode.
1213 Label done;
1214 GetVar(eax, var);
1215 __ cmp(eax, isolate()->factory()->the_hole_value());
1216 __ j(not_equal, &done, Label::kNear);
1217 __ push(Immediate(var->name()));
1218 __ CallRuntime(Runtime::kThrowReferenceError);
1219 __ bind(&done);
1220 context()->Plug(eax);
1221 break;
1222 }
1223 context()->Plug(var);
1224 break;
1225 }
1226
1227 case VariableLocation::LOOKUP: {
1228 Comment cmnt(masm_, "[ Lookup variable");
1229 Label done, slow;
1230 // Generate code for loading from variables potentially shadowed
1231 // by eval-introduced variables.
1232 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done);
1233 __ bind(&slow);
1234 __ push(Immediate(var->name()));
1235 Runtime::FunctionId function_id =
1236 typeof_mode == NOT_INSIDE_TYPEOF
1237 ? Runtime::kLoadLookupSlot
1238 : Runtime::kLoadLookupSlotInsideTypeof;
1239 __ CallRuntime(function_id);
1240 __ bind(&done);
1241 context()->Plug(eax);
1242 break;
1243 }
1244
1245 case VariableLocation::MODULE:
1246 UNREACHABLE();
1247 }
1248 }
1249
1250
EmitAccessor(ObjectLiteralProperty * property)1251 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) {
1252 Expression* expression = (property == NULL) ? NULL : property->value();
1253 if (expression == NULL) {
1254 PushOperand(isolate()->factory()->null_value());
1255 } else {
1256 VisitForStackValue(expression);
1257 if (NeedsHomeObject(expression)) {
1258 DCHECK(property->kind() == ObjectLiteral::Property::GETTER ||
1259 property->kind() == ObjectLiteral::Property::SETTER);
1260 int offset = property->kind() == ObjectLiteral::Property::GETTER ? 2 : 3;
1261 EmitSetHomeObject(expression, offset, property->GetSlot());
1262 }
1263 }
1264 }
1265
1266
VisitObjectLiteral(ObjectLiteral * expr)1267 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1268 Comment cmnt(masm_, "[ ObjectLiteral");
1269
1270 Handle<FixedArray> constant_properties = expr->constant_properties();
1271 int flags = expr->ComputeFlags();
1272 // If any of the keys would store to the elements array, then we shouldn't
1273 // allow it.
1274 if (MustCreateObjectLiteralWithRuntime(expr)) {
1275 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1276 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1277 __ push(Immediate(constant_properties));
1278 __ push(Immediate(Smi::FromInt(flags)));
1279 __ CallRuntime(Runtime::kCreateObjectLiteral);
1280 } else {
1281 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1282 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1283 __ mov(ecx, Immediate(constant_properties));
1284 __ mov(edx, Immediate(Smi::FromInt(flags)));
1285 FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
1286 __ CallStub(&stub);
1287 RestoreContext();
1288 }
1289 PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
1290
1291 // If result_saved is true the result is on top of the stack. If
1292 // result_saved is false the result is in eax.
1293 bool result_saved = false;
1294
1295 AccessorTable accessor_table(zone());
1296 int property_index = 0;
1297 for (; property_index < expr->properties()->length(); property_index++) {
1298 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1299 if (property->is_computed_name()) break;
1300 if (property->IsCompileTimeValue()) continue;
1301
1302 Literal* key = property->key()->AsLiteral();
1303 Expression* value = property->value();
1304 if (!result_saved) {
1305 PushOperand(eax); // Save result on the stack
1306 result_saved = true;
1307 }
1308 switch (property->kind()) {
1309 case ObjectLiteral::Property::CONSTANT:
1310 UNREACHABLE();
1311 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1312 DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
1313 // Fall through.
1314 case ObjectLiteral::Property::COMPUTED:
1315 // It is safe to use [[Put]] here because the boilerplate already
1316 // contains computed properties with an uninitialized value.
1317 if (key->IsStringLiteral()) {
1318 DCHECK(key->IsPropertyName());
1319 if (property->emit_store()) {
1320 VisitForAccumulatorValue(value);
1321 DCHECK(StoreDescriptor::ValueRegister().is(eax));
1322 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1323 CallStoreIC(property->GetSlot(0), key->value());
1324 PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS);
1325 if (NeedsHomeObject(value)) {
1326 EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1));
1327 }
1328 } else {
1329 VisitForEffect(value);
1330 }
1331 break;
1332 }
1333 PushOperand(Operand(esp, 0)); // Duplicate receiver.
1334 VisitForStackValue(key);
1335 VisitForStackValue(value);
1336 if (property->emit_store()) {
1337 if (NeedsHomeObject(value)) {
1338 EmitSetHomeObject(value, 2, property->GetSlot());
1339 }
1340 PushOperand(Smi::FromInt(SLOPPY)); // Language mode
1341 CallRuntimeWithOperands(Runtime::kSetProperty);
1342 } else {
1343 DropOperands(3);
1344 }
1345 break;
1346 case ObjectLiteral::Property::PROTOTYPE:
1347 PushOperand(Operand(esp, 0)); // Duplicate receiver.
1348 VisitForStackValue(value);
1349 DCHECK(property->emit_store());
1350 CallRuntimeWithOperands(Runtime::kInternalSetPrototype);
1351 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
1352 BailoutState::NO_REGISTERS);
1353 break;
1354 case ObjectLiteral::Property::GETTER:
1355 if (property->emit_store()) {
1356 AccessorTable::Iterator it = accessor_table.lookup(key);
1357 it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1358 it->second->getter = property;
1359 }
1360 break;
1361 case ObjectLiteral::Property::SETTER:
1362 if (property->emit_store()) {
1363 AccessorTable::Iterator it = accessor_table.lookup(key);
1364 it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1365 it->second->setter = property;
1366 }
1367 break;
1368 }
1369 }
1370
1371 // Emit code to define accessors, using only a single call to the runtime for
1372 // each pair of corresponding getters and setters.
1373 for (AccessorTable::Iterator it = accessor_table.begin();
1374 it != accessor_table.end();
1375 ++it) {
1376 PushOperand(Operand(esp, 0)); // Duplicate receiver.
1377 VisitForStackValue(it->first);
1378
1379 EmitAccessor(it->second->getter);
1380 EmitAccessor(it->second->setter);
1381
1382 PushOperand(Smi::FromInt(NONE));
1383 CallRuntimeWithOperands(Runtime::kDefineAccessorPropertyUnchecked);
1384 PrepareForBailoutForId(it->second->bailout_id, BailoutState::NO_REGISTERS);
1385 }
1386
1387 // Object literals have two parts. The "static" part on the left contains no
1388 // computed property names, and so we can compute its map ahead of time; see
1389 // runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
1390 // starts with the first computed property name, and continues with all
1391 // properties to its right. All the code from above initializes the static
1392 // component of the object literal, and arranges for the map of the result to
1393 // reflect the static order in which the keys appear. For the dynamic
1394 // properties, we compile them into a series of "SetOwnProperty" runtime
1395 // calls. This will preserve insertion order.
1396 for (; property_index < expr->properties()->length(); property_index++) {
1397 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1398
1399 Expression* value = property->value();
1400 if (!result_saved) {
1401 PushOperand(eax); // Save result on the stack
1402 result_saved = true;
1403 }
1404
1405 PushOperand(Operand(esp, 0)); // Duplicate receiver.
1406
1407 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
1408 DCHECK(!property->is_computed_name());
1409 VisitForStackValue(value);
1410 DCHECK(property->emit_store());
1411 CallRuntimeWithOperands(Runtime::kInternalSetPrototype);
1412 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
1413 BailoutState::NO_REGISTERS);
1414 } else {
1415 EmitPropertyKey(property, expr->GetIdForPropertyName(property_index));
1416 VisitForStackValue(value);
1417 if (NeedsHomeObject(value)) {
1418 EmitSetHomeObject(value, 2, property->GetSlot());
1419 }
1420
1421 switch (property->kind()) {
1422 case ObjectLiteral::Property::CONSTANT:
1423 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1424 case ObjectLiteral::Property::COMPUTED:
1425 if (property->emit_store()) {
1426 PushOperand(Smi::FromInt(NONE));
1427 PushOperand(Smi::FromInt(property->NeedsSetFunctionName()));
1428 CallRuntimeWithOperands(Runtime::kDefineDataPropertyInLiteral);
1429 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
1430 BailoutState::NO_REGISTERS);
1431 } else {
1432 DropOperands(3);
1433 }
1434 break;
1435
1436 case ObjectLiteral::Property::PROTOTYPE:
1437 UNREACHABLE();
1438 break;
1439
1440 case ObjectLiteral::Property::GETTER:
1441 PushOperand(Smi::FromInt(NONE));
1442 CallRuntimeWithOperands(Runtime::kDefineGetterPropertyUnchecked);
1443 break;
1444
1445 case ObjectLiteral::Property::SETTER:
1446 PushOperand(Smi::FromInt(NONE));
1447 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
1448 break;
1449 }
1450 }
1451 }
1452
1453 if (result_saved) {
1454 context()->PlugTOS();
1455 } else {
1456 context()->Plug(eax);
1457 }
1458 }
1459
1460
VisitArrayLiteral(ArrayLiteral * expr)1461 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1462 Comment cmnt(masm_, "[ ArrayLiteral");
1463
1464 Handle<FixedArray> constant_elements = expr->constant_elements();
1465 bool has_constant_fast_elements =
1466 IsFastObjectElementsKind(expr->constant_elements_kind());
1467
1468 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
1469 if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) {
1470 // If the only customer of allocation sites is transitioning, then
1471 // we can turn it off if we don't have anywhere else to transition to.
1472 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1473 }
1474
1475 if (MustCreateArrayLiteralWithRuntime(expr)) {
1476 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1477 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1478 __ push(Immediate(constant_elements));
1479 __ push(Immediate(Smi::FromInt(expr->ComputeFlags())));
1480 __ CallRuntime(Runtime::kCreateArrayLiteral);
1481 } else {
1482 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1483 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1484 __ mov(ecx, Immediate(constant_elements));
1485 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
1486 __ CallStub(&stub);
1487 RestoreContext();
1488 }
1489 PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
1490
1491 bool result_saved = false; // Is the result saved to the stack?
1492 ZoneList<Expression*>* subexprs = expr->values();
1493 int length = subexprs->length();
1494
1495 // Emit code to evaluate all the non-constant subexpressions and to store
1496 // them into the newly cloned array.
1497 for (int array_index = 0; array_index < length; array_index++) {
1498 Expression* subexpr = subexprs->at(array_index);
1499 DCHECK(!subexpr->IsSpread());
1500
1501 // If the subexpression is a literal or a simple materialized literal it
1502 // is already set in the cloned array.
1503 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1504
1505 if (!result_saved) {
1506 PushOperand(eax); // array literal.
1507 result_saved = true;
1508 }
1509 VisitForAccumulatorValue(subexpr);
1510
1511 __ mov(StoreDescriptor::NameRegister(),
1512 Immediate(Smi::FromInt(array_index)));
1513 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1514 CallKeyedStoreIC(expr->LiteralFeedbackSlot());
1515 PrepareForBailoutForId(expr->GetIdForElement(array_index),
1516 BailoutState::NO_REGISTERS);
1517 }
1518
1519 if (result_saved) {
1520 context()->PlugTOS();
1521 } else {
1522 context()->Plug(eax);
1523 }
1524 }
1525
1526
VisitAssignment(Assignment * expr)1527 void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1528 DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
1529
1530 Comment cmnt(masm_, "[ Assignment");
1531
1532 Property* property = expr->target()->AsProperty();
1533 LhsKind assign_type = Property::GetAssignType(property);
1534
1535 // Evaluate LHS expression.
1536 switch (assign_type) {
1537 case VARIABLE:
1538 // Nothing to do here.
1539 break;
1540 case NAMED_SUPER_PROPERTY:
1541 VisitForStackValue(
1542 property->obj()->AsSuperPropertyReference()->this_var());
1543 VisitForAccumulatorValue(
1544 property->obj()->AsSuperPropertyReference()->home_object());
1545 PushOperand(result_register());
1546 if (expr->is_compound()) {
1547 PushOperand(MemOperand(esp, kPointerSize));
1548 PushOperand(result_register());
1549 }
1550 break;
1551 case NAMED_PROPERTY:
1552 if (expr->is_compound()) {
1553 // We need the receiver both on the stack and in the register.
1554 VisitForStackValue(property->obj());
1555 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
1556 } else {
1557 VisitForStackValue(property->obj());
1558 }
1559 break;
1560 case KEYED_SUPER_PROPERTY:
1561 VisitForStackValue(
1562 property->obj()->AsSuperPropertyReference()->this_var());
1563 VisitForStackValue(
1564 property->obj()->AsSuperPropertyReference()->home_object());
1565 VisitForAccumulatorValue(property->key());
1566 PushOperand(result_register());
1567 if (expr->is_compound()) {
1568 PushOperand(MemOperand(esp, 2 * kPointerSize));
1569 PushOperand(MemOperand(esp, 2 * kPointerSize));
1570 PushOperand(result_register());
1571 }
1572 break;
1573 case KEYED_PROPERTY: {
1574 if (expr->is_compound()) {
1575 VisitForStackValue(property->obj());
1576 VisitForStackValue(property->key());
1577 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, kPointerSize));
1578 __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0));
1579 } else {
1580 VisitForStackValue(property->obj());
1581 VisitForStackValue(property->key());
1582 }
1583 break;
1584 }
1585 }
1586
1587 // For compound assignments we need another deoptimization point after the
1588 // variable/property load.
1589 if (expr->is_compound()) {
1590 AccumulatorValueContext result_context(this);
1591 { AccumulatorValueContext left_operand_context(this);
1592 switch (assign_type) {
1593 case VARIABLE:
1594 EmitVariableLoad(expr->target()->AsVariableProxy());
1595 PrepareForBailout(expr->target(), BailoutState::TOS_REGISTER);
1596 break;
1597 case NAMED_SUPER_PROPERTY:
1598 EmitNamedSuperPropertyLoad(property);
1599 PrepareForBailoutForId(property->LoadId(),
1600 BailoutState::TOS_REGISTER);
1601 break;
1602 case NAMED_PROPERTY:
1603 EmitNamedPropertyLoad(property);
1604 PrepareForBailoutForId(property->LoadId(),
1605 BailoutState::TOS_REGISTER);
1606 break;
1607 case KEYED_SUPER_PROPERTY:
1608 EmitKeyedSuperPropertyLoad(property);
1609 PrepareForBailoutForId(property->LoadId(),
1610 BailoutState::TOS_REGISTER);
1611 break;
1612 case KEYED_PROPERTY:
1613 EmitKeyedPropertyLoad(property);
1614 PrepareForBailoutForId(property->LoadId(),
1615 BailoutState::TOS_REGISTER);
1616 break;
1617 }
1618 }
1619
1620 Token::Value op = expr->binary_op();
1621 PushOperand(eax); // Left operand goes on the stack.
1622 VisitForAccumulatorValue(expr->value());
1623
1624 if (ShouldInlineSmiCase(op)) {
1625 EmitInlineSmiBinaryOp(expr->binary_operation(),
1626 op,
1627 expr->target(),
1628 expr->value());
1629 } else {
1630 EmitBinaryOp(expr->binary_operation(), op);
1631 }
1632
1633 // Deoptimization point in case the binary operation may have side effects.
1634 PrepareForBailout(expr->binary_operation(), BailoutState::TOS_REGISTER);
1635 } else {
1636 VisitForAccumulatorValue(expr->value());
1637 }
1638
1639 SetExpressionPosition(expr);
1640
1641 // Store the value.
1642 switch (assign_type) {
1643 case VARIABLE: {
1644 VariableProxy* proxy = expr->target()->AsVariableProxy();
1645 EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(),
1646 proxy->hole_check_mode());
1647 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
1648 context()->Plug(eax);
1649 break;
1650 }
1651 case NAMED_PROPERTY:
1652 EmitNamedPropertyAssignment(expr);
1653 break;
1654 case NAMED_SUPER_PROPERTY:
1655 EmitNamedSuperPropertyStore(property);
1656 context()->Plug(result_register());
1657 break;
1658 case KEYED_SUPER_PROPERTY:
1659 EmitKeyedSuperPropertyStore(property);
1660 context()->Plug(result_register());
1661 break;
1662 case KEYED_PROPERTY:
1663 EmitKeyedPropertyAssignment(expr);
1664 break;
1665 }
1666 }
1667
1668
VisitYield(Yield * expr)1669 void FullCodeGenerator::VisitYield(Yield* expr) {
1670 Comment cmnt(masm_, "[ Yield");
1671 SetExpressionPosition(expr);
1672
1673 // Evaluate yielded value first; the initial iterator definition depends on
1674 // this. It stays on the stack while we update the iterator.
1675 VisitForStackValue(expr->expression());
1676
1677 Label suspend, continuation, post_runtime, resume, exception;
1678
1679 __ jmp(&suspend);
1680 __ bind(&continuation);
1681 // When we arrive here, eax holds the generator object.
1682 __ RecordGeneratorContinuation();
1683 __ mov(ebx, FieldOperand(eax, JSGeneratorObject::kResumeModeOffset));
1684 __ mov(eax, FieldOperand(eax, JSGeneratorObject::kInputOrDebugPosOffset));
1685 STATIC_ASSERT(JSGeneratorObject::kNext < JSGeneratorObject::kReturn);
1686 STATIC_ASSERT(JSGeneratorObject::kThrow > JSGeneratorObject::kReturn);
1687 __ cmp(ebx, Immediate(Smi::FromInt(JSGeneratorObject::kReturn)));
1688 __ j(less, &resume);
1689 __ Push(result_register());
1690 __ j(greater, &exception);
1691 EmitCreateIteratorResult(true);
1692 EmitUnwindAndReturn();
1693
1694 __ bind(&exception);
1695 __ CallRuntime(expr->rethrow_on_exception() ? Runtime::kReThrow
1696 : Runtime::kThrow);
1697
1698 __ bind(&suspend);
1699 OperandStackDepthIncrement(1); // Not popped on this path.
1700 VisitForAccumulatorValue(expr->generator_object());
1701 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
1702 __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
1703 Immediate(Smi::FromInt(continuation.pos())));
1704 __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
1705 __ mov(ecx, esi);
1706 __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
1707 kDontSaveFPRegs);
1708 __ lea(ebx, Operand(ebp, StandardFrameConstants::kExpressionsOffset));
1709 __ cmp(esp, ebx);
1710 __ j(equal, &post_runtime);
1711 __ push(eax); // generator object
1712 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
1713 RestoreContext();
1714 __ bind(&post_runtime);
1715 PopOperand(result_register());
1716 EmitReturnSequence();
1717
1718 __ bind(&resume);
1719 context()->Plug(result_register());
1720 }
1721
PushOperand(MemOperand operand)1722 void FullCodeGenerator::PushOperand(MemOperand operand) {
1723 OperandStackDepthIncrement(1);
1724 __ Push(operand);
1725 }
1726
EmitOperandStackDepthCheck()1727 void FullCodeGenerator::EmitOperandStackDepthCheck() {
1728 if (FLAG_debug_code) {
1729 int expected_diff = StandardFrameConstants::kFixedFrameSizeFromFp +
1730 operand_stack_depth_ * kPointerSize;
1731 __ mov(eax, ebp);
1732 __ sub(eax, esp);
1733 __ cmp(eax, Immediate(expected_diff));
1734 __ Assert(equal, kUnexpectedStackDepth);
1735 }
1736 }
1737
EmitCreateIteratorResult(bool done)1738 void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
1739 Label allocate, done_allocate;
1740
1741 __ Allocate(JSIteratorResult::kSize, eax, ecx, edx, &allocate,
1742 NO_ALLOCATION_FLAGS);
1743 __ jmp(&done_allocate, Label::kNear);
1744
1745 __ bind(&allocate);
1746 __ Push(Smi::FromInt(JSIteratorResult::kSize));
1747 __ CallRuntime(Runtime::kAllocateInNewSpace);
1748
1749 __ bind(&done_allocate);
1750 __ mov(ebx, NativeContextOperand());
1751 __ mov(ebx, ContextOperand(ebx, Context::ITERATOR_RESULT_MAP_INDEX));
1752 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
1753 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
1754 isolate()->factory()->empty_fixed_array());
1755 __ mov(FieldOperand(eax, JSObject::kElementsOffset),
1756 isolate()->factory()->empty_fixed_array());
1757 __ pop(FieldOperand(eax, JSIteratorResult::kValueOffset));
1758 __ mov(FieldOperand(eax, JSIteratorResult::kDoneOffset),
1759 isolate()->factory()->ToBoolean(done));
1760 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
1761 OperandStackDepthDecrement(1);
1762 }
1763
1764
EmitInlineSmiBinaryOp(BinaryOperation * expr,Token::Value op,Expression * left,Expression * right)1765 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
1766 Token::Value op,
1767 Expression* left,
1768 Expression* right) {
1769 // Do combined smi check of the operands. Left operand is on the
1770 // stack. Right operand is in eax.
1771 Label smi_case, done, stub_call;
1772 PopOperand(edx);
1773 __ mov(ecx, eax);
1774 __ or_(eax, edx);
1775 JumpPatchSite patch_site(masm_);
1776 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
1777
1778 __ bind(&stub_call);
1779 __ mov(eax, ecx);
1780 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
1781 CallIC(code, expr->BinaryOperationFeedbackId());
1782 patch_site.EmitPatchInfo();
1783 __ jmp(&done, Label::kNear);
1784
1785 // Smi case.
1786 __ bind(&smi_case);
1787 __ mov(eax, edx); // Copy left operand in case of a stub call.
1788
1789 switch (op) {
1790 case Token::SAR:
1791 __ SmiUntag(ecx);
1792 __ sar_cl(eax); // No checks of result necessary
1793 __ and_(eax, Immediate(~kSmiTagMask));
1794 break;
1795 case Token::SHL: {
1796 Label result_ok;
1797 __ SmiUntag(eax);
1798 __ SmiUntag(ecx);
1799 __ shl_cl(eax);
1800 // Check that the *signed* result fits in a smi.
1801 __ cmp(eax, 0xc0000000);
1802 __ j(positive, &result_ok);
1803 __ SmiTag(ecx);
1804 __ jmp(&stub_call);
1805 __ bind(&result_ok);
1806 __ SmiTag(eax);
1807 break;
1808 }
1809 case Token::SHR: {
1810 Label result_ok;
1811 __ SmiUntag(eax);
1812 __ SmiUntag(ecx);
1813 __ shr_cl(eax);
1814 __ test(eax, Immediate(0xc0000000));
1815 __ j(zero, &result_ok);
1816 __ SmiTag(ecx);
1817 __ jmp(&stub_call);
1818 __ bind(&result_ok);
1819 __ SmiTag(eax);
1820 break;
1821 }
1822 case Token::ADD:
1823 __ add(eax, ecx);
1824 __ j(overflow, &stub_call);
1825 break;
1826 case Token::SUB:
1827 __ sub(eax, ecx);
1828 __ j(overflow, &stub_call);
1829 break;
1830 case Token::MUL: {
1831 __ SmiUntag(eax);
1832 __ imul(eax, ecx);
1833 __ j(overflow, &stub_call);
1834 __ test(eax, eax);
1835 __ j(not_zero, &done, Label::kNear);
1836 __ mov(ebx, edx);
1837 __ or_(ebx, ecx);
1838 __ j(negative, &stub_call);
1839 break;
1840 }
1841 case Token::BIT_OR:
1842 __ or_(eax, ecx);
1843 break;
1844 case Token::BIT_AND:
1845 __ and_(eax, ecx);
1846 break;
1847 case Token::BIT_XOR:
1848 __ xor_(eax, ecx);
1849 break;
1850 default:
1851 UNREACHABLE();
1852 }
1853
1854 __ bind(&done);
1855 context()->Plug(eax);
1856 }
1857
1858
EmitClassDefineProperties(ClassLiteral * lit)1859 void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
1860 for (int i = 0; i < lit->properties()->length(); i++) {
1861 ClassLiteral::Property* property = lit->properties()->at(i);
1862 Expression* value = property->value();
1863
1864 if (property->is_static()) {
1865 PushOperand(Operand(esp, kPointerSize)); // constructor
1866 } else {
1867 PushOperand(Operand(esp, 0)); // prototype
1868 }
1869 EmitPropertyKey(property, lit->GetIdForProperty(i));
1870
1871 // The static prototype property is read only. We handle the non computed
1872 // property name case in the parser. Since this is the only case where we
1873 // need to check for an own read only property we special case this so we do
1874 // not need to do this for every property.
1875 if (property->is_static() && property->is_computed_name()) {
1876 __ CallRuntime(Runtime::kThrowIfStaticPrototype);
1877 __ push(eax);
1878 }
1879
1880 VisitForStackValue(value);
1881 if (NeedsHomeObject(value)) {
1882 EmitSetHomeObject(value, 2, property->GetSlot());
1883 }
1884
1885 switch (property->kind()) {
1886 case ClassLiteral::Property::METHOD:
1887 PushOperand(Smi::FromInt(DONT_ENUM));
1888 PushOperand(Smi::FromInt(property->NeedsSetFunctionName()));
1889 CallRuntimeWithOperands(Runtime::kDefineDataPropertyInLiteral);
1890 break;
1891
1892 case ClassLiteral::Property::GETTER:
1893 PushOperand(Smi::FromInt(DONT_ENUM));
1894 CallRuntimeWithOperands(Runtime::kDefineGetterPropertyUnchecked);
1895 break;
1896
1897 case ClassLiteral::Property::SETTER:
1898 PushOperand(Smi::FromInt(DONT_ENUM));
1899 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
1900 break;
1901
1902 case ClassLiteral::Property::FIELD:
1903 UNREACHABLE();
1904 break;
1905 }
1906 }
1907 }
1908
1909
EmitBinaryOp(BinaryOperation * expr,Token::Value op)1910 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
1911 PopOperand(edx);
1912 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
1913 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
1914 CallIC(code, expr->BinaryOperationFeedbackId());
1915 patch_site.EmitPatchInfo();
1916 context()->Plug(eax);
1917 }
1918
1919
EmitAssignment(Expression * expr,FeedbackVectorSlot slot)1920 void FullCodeGenerator::EmitAssignment(Expression* expr,
1921 FeedbackVectorSlot slot) {
1922 DCHECK(expr->IsValidReferenceExpressionOrThis());
1923
1924 Property* prop = expr->AsProperty();
1925 LhsKind assign_type = Property::GetAssignType(prop);
1926
1927 switch (assign_type) {
1928 case VARIABLE: {
1929 VariableProxy* proxy = expr->AsVariableProxy();
1930 EffectContext context(this);
1931 EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot,
1932 proxy->hole_check_mode());
1933 break;
1934 }
1935 case NAMED_PROPERTY: {
1936 PushOperand(eax); // Preserve value.
1937 VisitForAccumulatorValue(prop->obj());
1938 __ Move(StoreDescriptor::ReceiverRegister(), eax);
1939 PopOperand(StoreDescriptor::ValueRegister()); // Restore value.
1940 CallStoreIC(slot, prop->key()->AsLiteral()->value());
1941 break;
1942 }
1943 case NAMED_SUPER_PROPERTY: {
1944 PushOperand(eax);
1945 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
1946 VisitForAccumulatorValue(
1947 prop->obj()->AsSuperPropertyReference()->home_object());
1948 // stack: value, this; eax: home_object
1949 Register scratch = ecx;
1950 Register scratch2 = edx;
1951 __ mov(scratch, result_register()); // home_object
1952 __ mov(eax, MemOperand(esp, kPointerSize)); // value
1953 __ mov(scratch2, MemOperand(esp, 0)); // this
1954 __ mov(MemOperand(esp, kPointerSize), scratch2); // this
1955 __ mov(MemOperand(esp, 0), scratch); // home_object
1956 // stack: this, home_object. eax: value
1957 EmitNamedSuperPropertyStore(prop);
1958 break;
1959 }
1960 case KEYED_SUPER_PROPERTY: {
1961 PushOperand(eax);
1962 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
1963 VisitForStackValue(
1964 prop->obj()->AsSuperPropertyReference()->home_object());
1965 VisitForAccumulatorValue(prop->key());
1966 Register scratch = ecx;
1967 Register scratch2 = edx;
1968 __ mov(scratch2, MemOperand(esp, 2 * kPointerSize)); // value
1969 // stack: value, this, home_object; eax: key, edx: value
1970 __ mov(scratch, MemOperand(esp, kPointerSize)); // this
1971 __ mov(MemOperand(esp, 2 * kPointerSize), scratch);
1972 __ mov(scratch, MemOperand(esp, 0)); // home_object
1973 __ mov(MemOperand(esp, kPointerSize), scratch);
1974 __ mov(MemOperand(esp, 0), eax);
1975 __ mov(eax, scratch2);
1976 // stack: this, home_object, key; eax: value.
1977 EmitKeyedSuperPropertyStore(prop);
1978 break;
1979 }
1980 case KEYED_PROPERTY: {
1981 PushOperand(eax); // Preserve value.
1982 VisitForStackValue(prop->obj());
1983 VisitForAccumulatorValue(prop->key());
1984 __ Move(StoreDescriptor::NameRegister(), eax);
1985 PopOperand(StoreDescriptor::ReceiverRegister()); // Receiver.
1986 PopOperand(StoreDescriptor::ValueRegister()); // Restore value.
1987 CallKeyedStoreIC(slot);
1988 break;
1989 }
1990 }
1991 context()->Plug(eax);
1992 }
1993
1994
EmitStoreToStackLocalOrContextSlot(Variable * var,MemOperand location)1995 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
1996 Variable* var, MemOperand location) {
1997 __ mov(location, eax);
1998 if (var->IsContextSlot()) {
1999 __ mov(edx, eax);
2000 int offset = Context::SlotOffset(var->index());
2001 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
2002 }
2003 }
2004
EmitVariableAssignment(Variable * var,Token::Value op,FeedbackVectorSlot slot,HoleCheckMode hole_check_mode)2005 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
2006 FeedbackVectorSlot slot,
2007 HoleCheckMode hole_check_mode) {
2008 if (var->IsUnallocated()) {
2009 // Global var, const, or let.
2010 __ mov(StoreDescriptor::ReceiverRegister(), NativeContextOperand());
2011 __ mov(StoreDescriptor::ReceiverRegister(),
2012 ContextOperand(StoreDescriptor::ReceiverRegister(),
2013 Context::EXTENSION_INDEX));
2014 CallStoreIC(slot, var->name());
2015
2016 } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) {
2017 DCHECK(!var->IsLookupSlot());
2018 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2019 MemOperand location = VarOperand(var, ecx);
2020 // Perform an initialization check for lexically declared variables.
2021 if (hole_check_mode == HoleCheckMode::kRequired) {
2022 Label assign;
2023 __ mov(edx, location);
2024 __ cmp(edx, isolate()->factory()->the_hole_value());
2025 __ j(not_equal, &assign, Label::kNear);
2026 __ push(Immediate(var->name()));
2027 __ CallRuntime(Runtime::kThrowReferenceError);
2028 __ bind(&assign);
2029 }
2030 if (var->mode() != CONST) {
2031 EmitStoreToStackLocalOrContextSlot(var, location);
2032 } else if (var->throw_on_const_assignment(language_mode())) {
2033 __ CallRuntime(Runtime::kThrowConstAssignError);
2034 }
2035 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
2036 // Initializing assignment to const {this} needs a write barrier.
2037 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2038 Label uninitialized_this;
2039 MemOperand location = VarOperand(var, ecx);
2040 __ mov(edx, location);
2041 __ cmp(edx, isolate()->factory()->the_hole_value());
2042 __ j(equal, &uninitialized_this);
2043 __ push(Immediate(var->name()));
2044 __ CallRuntime(Runtime::kThrowReferenceError);
2045 __ bind(&uninitialized_this);
2046 EmitStoreToStackLocalOrContextSlot(var, location);
2047
2048 } else {
2049 DCHECK(var->mode() != CONST || op == Token::INIT);
2050 if (var->IsLookupSlot()) {
2051 // Assignment to var.
2052 __ Push(Immediate(var->name()));
2053 __ Push(eax);
2054 __ CallRuntime(is_strict(language_mode())
2055 ? Runtime::kStoreLookupSlot_Strict
2056 : Runtime::kStoreLookupSlot_Sloppy);
2057 } else {
2058 // Assignment to var or initializing assignment to let/const in harmony
2059 // mode.
2060 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2061 MemOperand location = VarOperand(var, ecx);
2062 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) {
2063 // Check for an uninitialized let binding.
2064 __ mov(edx, location);
2065 __ cmp(edx, isolate()->factory()->the_hole_value());
2066 __ Check(equal, kLetBindingReInitialization);
2067 }
2068 EmitStoreToStackLocalOrContextSlot(var, location);
2069 }
2070 }
2071 }
2072
2073
EmitNamedPropertyAssignment(Assignment * expr)2074 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2075 // Assignment to a property, using a named store IC.
2076 // eax : value
2077 // esp[0] : receiver
2078 Property* prop = expr->target()->AsProperty();
2079 DCHECK(prop != NULL);
2080 DCHECK(prop->key()->IsLiteral());
2081
2082 PopOperand(StoreDescriptor::ReceiverRegister());
2083 CallStoreIC(expr->AssignmentSlot(), prop->key()->AsLiteral()->value());
2084 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
2085 context()->Plug(eax);
2086 }
2087
2088
EmitNamedSuperPropertyStore(Property * prop)2089 void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
2090 // Assignment to named property of super.
2091 // eax : value
2092 // stack : receiver ('this'), home_object
2093 DCHECK(prop != NULL);
2094 Literal* key = prop->key()->AsLiteral();
2095 DCHECK(key != NULL);
2096
2097 PushOperand(key->value());
2098 PushOperand(eax);
2099 CallRuntimeWithOperands(is_strict(language_mode())
2100 ? Runtime::kStoreToSuper_Strict
2101 : Runtime::kStoreToSuper_Sloppy);
2102 }
2103
2104
EmitKeyedSuperPropertyStore(Property * prop)2105 void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
2106 // Assignment to named property of super.
2107 // eax : value
2108 // stack : receiver ('this'), home_object, key
2109
2110 PushOperand(eax);
2111 CallRuntimeWithOperands(is_strict(language_mode())
2112 ? Runtime::kStoreKeyedToSuper_Strict
2113 : Runtime::kStoreKeyedToSuper_Sloppy);
2114 }
2115
2116
EmitKeyedPropertyAssignment(Assignment * expr)2117 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2118 // Assignment to a property, using a keyed store IC.
2119 // eax : value
2120 // esp[0] : key
2121 // esp[kPointerSize] : receiver
2122
2123 PopOperand(StoreDescriptor::NameRegister()); // Key.
2124 PopOperand(StoreDescriptor::ReceiverRegister());
2125 DCHECK(StoreDescriptor::ValueRegister().is(eax));
2126 CallKeyedStoreIC(expr->AssignmentSlot());
2127 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
2128 context()->Plug(eax);
2129 }
2130
2131 // Code common for calls using the IC.
EmitCallWithLoadIC(Call * expr)2132 void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
2133 Expression* callee = expr->expression();
2134
2135 // Get the target function.
2136 ConvertReceiverMode convert_mode;
2137 if (callee->IsVariableProxy()) {
2138 { StackValueContext context(this);
2139 EmitVariableLoad(callee->AsVariableProxy());
2140 PrepareForBailout(callee, BailoutState::NO_REGISTERS);
2141 }
2142 // Push undefined as receiver. This is patched in the method prologue if it
2143 // is a sloppy mode method.
2144 PushOperand(isolate()->factory()->undefined_value());
2145 convert_mode = ConvertReceiverMode::kNullOrUndefined;
2146 } else {
2147 // Load the function from the receiver.
2148 DCHECK(callee->IsProperty());
2149 DCHECK(!callee->AsProperty()->IsSuperAccess());
2150 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
2151 EmitNamedPropertyLoad(callee->AsProperty());
2152 PrepareForBailoutForId(callee->AsProperty()->LoadId(),
2153 BailoutState::TOS_REGISTER);
2154 // Push the target function under the receiver.
2155 PushOperand(Operand(esp, 0));
2156 __ mov(Operand(esp, kPointerSize), eax);
2157 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
2158 }
2159
2160 EmitCall(expr, convert_mode);
2161 }
2162
2163
EmitSuperCallWithLoadIC(Call * expr)2164 void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
2165 SetExpressionPosition(expr);
2166 Expression* callee = expr->expression();
2167 DCHECK(callee->IsProperty());
2168 Property* prop = callee->AsProperty();
2169 DCHECK(prop->IsSuperAccess());
2170
2171 Literal* key = prop->key()->AsLiteral();
2172 DCHECK(!key->value()->IsSmi());
2173 // Load the function from the receiver.
2174 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2175 VisitForStackValue(super_ref->home_object());
2176 VisitForAccumulatorValue(super_ref->this_var());
2177 PushOperand(eax);
2178 PushOperand(eax);
2179 PushOperand(Operand(esp, kPointerSize * 2));
2180 PushOperand(key->value());
2181 // Stack here:
2182 // - home_object
2183 // - this (receiver)
2184 // - this (receiver) <-- LoadFromSuper will pop here and below.
2185 // - home_object
2186 // - key
2187 CallRuntimeWithOperands(Runtime::kLoadFromSuper);
2188 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
2189
2190 // Replace home_object with target function.
2191 __ mov(Operand(esp, kPointerSize), eax);
2192
2193 // Stack here:
2194 // - target function
2195 // - this (receiver)
2196 EmitCall(expr);
2197 }
2198
2199
2200 // Code common for calls using the IC.
EmitKeyedCallWithLoadIC(Call * expr,Expression * key)2201 void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
2202 Expression* key) {
2203 // Load the key.
2204 VisitForAccumulatorValue(key);
2205
2206 Expression* callee = expr->expression();
2207
2208 // Load the function from the receiver.
2209 DCHECK(callee->IsProperty());
2210 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
2211 __ mov(LoadDescriptor::NameRegister(), eax);
2212 EmitKeyedPropertyLoad(callee->AsProperty());
2213 PrepareForBailoutForId(callee->AsProperty()->LoadId(),
2214 BailoutState::TOS_REGISTER);
2215
2216 // Push the target function under the receiver.
2217 PushOperand(Operand(esp, 0));
2218 __ mov(Operand(esp, kPointerSize), eax);
2219
2220 EmitCall(expr, ConvertReceiverMode::kNotNullOrUndefined);
2221 }
2222
2223
EmitKeyedSuperCallWithLoadIC(Call * expr)2224 void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
2225 Expression* callee = expr->expression();
2226 DCHECK(callee->IsProperty());
2227 Property* prop = callee->AsProperty();
2228 DCHECK(prop->IsSuperAccess());
2229
2230 SetExpressionPosition(prop);
2231 // Load the function from the receiver.
2232 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2233 VisitForStackValue(super_ref->home_object());
2234 VisitForAccumulatorValue(super_ref->this_var());
2235 PushOperand(eax);
2236 PushOperand(eax);
2237 PushOperand(Operand(esp, kPointerSize * 2));
2238 VisitForStackValue(prop->key());
2239 // Stack here:
2240 // - home_object
2241 // - this (receiver)
2242 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
2243 // - home_object
2244 // - key
2245 CallRuntimeWithOperands(Runtime::kLoadKeyedFromSuper);
2246 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
2247
2248 // Replace home_object with target function.
2249 __ mov(Operand(esp, kPointerSize), eax);
2250
2251 // Stack here:
2252 // - target function
2253 // - this (receiver)
2254 EmitCall(expr);
2255 }
2256
2257
EmitCall(Call * expr,ConvertReceiverMode mode)2258 void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
2259 // Load the arguments.
2260 ZoneList<Expression*>* args = expr->arguments();
2261 int arg_count = args->length();
2262 for (int i = 0; i < arg_count; i++) {
2263 VisitForStackValue(args->at(i));
2264 }
2265
2266 PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
2267 SetCallPosition(expr, expr->tail_call_mode());
2268 if (expr->tail_call_mode() == TailCallMode::kAllow) {
2269 if (FLAG_trace) {
2270 __ CallRuntime(Runtime::kTraceTailCall);
2271 }
2272 // Update profiling counters before the tail call since we will
2273 // not return to this function.
2274 EmitProfilingCounterHandlingForReturnSequence(true);
2275 }
2276 Handle<Code> code =
2277 CodeFactory::CallIC(isolate(), mode, expr->tail_call_mode()).code();
2278 __ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackICSlot())));
2279 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2280 __ Move(eax, Immediate(arg_count));
2281 CallIC(code);
2282 OperandStackDepthDecrement(arg_count + 1);
2283
2284 RecordJSReturnSite(expr);
2285 RestoreContext();
2286 context()->DropAndPlug(1, eax);
2287 }
2288
EmitResolvePossiblyDirectEval(Call * expr)2289 void FullCodeGenerator::EmitResolvePossiblyDirectEval(Call* expr) {
2290 int arg_count = expr->arguments()->length();
2291 // Push copy of the first argument or undefined if it doesn't exist.
2292 if (arg_count > 0) {
2293 __ push(Operand(esp, arg_count * kPointerSize));
2294 } else {
2295 __ push(Immediate(isolate()->factory()->undefined_value()));
2296 }
2297
2298 // Push the enclosing function.
2299 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2300
2301 // Push the language mode.
2302 __ push(Immediate(Smi::FromInt(language_mode())));
2303
2304 // Push the start position of the scope the calls resides in.
2305 __ push(Immediate(Smi::FromInt(scope()->start_position())));
2306
2307 // Push the source position of the eval call.
2308 __ push(Immediate(Smi::FromInt(expr->position())));
2309
2310 // Do the runtime call.
2311 __ CallRuntime(Runtime::kResolvePossiblyDirectEval);
2312 }
2313
2314
2315 // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
PushCalleeAndWithBaseObject(Call * expr)2316 void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
2317 VariableProxy* callee = expr->expression()->AsVariableProxy();
2318 if (callee->var()->IsLookupSlot()) {
2319 Label slow, done;
2320 SetExpressionPosition(callee);
2321 // Generate code for loading from variables potentially shadowed by
2322 // eval-introduced variables.
2323 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
2324
2325 __ bind(&slow);
2326 // Call the runtime to find the function to call (returned in eax) and
2327 // the object holding it (returned in edx).
2328 __ Push(callee->name());
2329 __ CallRuntime(Runtime::kLoadLookupSlotForCall);
2330 PushOperand(eax); // Function.
2331 PushOperand(edx); // Receiver.
2332 PrepareForBailoutForId(expr->LookupId(), BailoutState::NO_REGISTERS);
2333
2334 // If fast case code has been generated, emit code to push the function
2335 // and receiver and have the slow path jump around this code.
2336 if (done.is_linked()) {
2337 Label call;
2338 __ jmp(&call, Label::kNear);
2339 __ bind(&done);
2340 // Push function.
2341 __ push(eax);
2342 // The receiver is implicitly the global receiver. Indicate this by
2343 // passing the hole to the call function stub.
2344 __ push(Immediate(isolate()->factory()->undefined_value()));
2345 __ bind(&call);
2346 }
2347 } else {
2348 VisitForStackValue(callee);
2349 // refEnv.WithBaseObject()
2350 PushOperand(isolate()->factory()->undefined_value());
2351 }
2352 }
2353
2354
EmitPossiblyEvalCall(Call * expr)2355 void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
2356 // In a call to eval, we first call Runtime_ResolvePossiblyDirectEval
2357 // to resolve the function we need to call. Then we call the resolved
2358 // function using the given arguments.
2359 ZoneList<Expression*>* args = expr->arguments();
2360 int arg_count = args->length();
2361
2362 PushCalleeAndWithBaseObject(expr);
2363
2364 // Push the arguments.
2365 for (int i = 0; i < arg_count; i++) {
2366 VisitForStackValue(args->at(i));
2367 }
2368
2369 // Push a copy of the function (found below the arguments) and
2370 // resolve eval.
2371 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
2372 EmitResolvePossiblyDirectEval(expr);
2373
2374 // Touch up the stack with the resolved function.
2375 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
2376
2377 PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS);
2378
2379 SetCallPosition(expr);
2380 Handle<Code> code = CodeFactory::CallIC(isolate(), ConvertReceiverMode::kAny,
2381 expr->tail_call_mode())
2382 .code();
2383 __ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackICSlot())));
2384 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2385 __ Move(eax, Immediate(arg_count));
2386 __ call(code, RelocInfo::CODE_TARGET);
2387 OperandStackDepthDecrement(arg_count + 1);
2388 RecordJSReturnSite(expr);
2389 RestoreContext();
2390 context()->DropAndPlug(1, eax);
2391 }
2392
2393
VisitCallNew(CallNew * expr)2394 void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2395 Comment cmnt(masm_, "[ CallNew");
2396 // According to ECMA-262, section 11.2.2, page 44, the function
2397 // expression in new calls must be evaluated before the
2398 // arguments.
2399
2400 // Push constructor on the stack. If it's not a function it's used as
2401 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2402 // ignored.
2403 DCHECK(!expr->expression()->IsSuperPropertyReference());
2404 VisitForStackValue(expr->expression());
2405
2406 // Push the arguments ("left-to-right") on the stack.
2407 ZoneList<Expression*>* args = expr->arguments();
2408 int arg_count = args->length();
2409 for (int i = 0; i < arg_count; i++) {
2410 VisitForStackValue(args->at(i));
2411 }
2412
2413 // Call the construct call builtin that handles allocation and
2414 // constructor invocation.
2415 SetConstructCallPosition(expr);
2416
2417 // Load function and argument count into edi and eax.
2418 __ Move(eax, Immediate(arg_count));
2419 __ mov(edi, Operand(esp, arg_count * kPointerSize));
2420
2421 // Record call targets in unoptimized code.
2422 __ EmitLoadTypeFeedbackVector(ebx);
2423 __ mov(edx, Immediate(SmiFromSlot(expr->CallNewFeedbackSlot())));
2424
2425 CallConstructStub stub(isolate());
2426 CallIC(stub.GetCode());
2427 OperandStackDepthDecrement(arg_count + 1);
2428 PrepareForBailoutForId(expr->ReturnId(), BailoutState::TOS_REGISTER);
2429 RestoreContext();
2430 context()->Plug(eax);
2431 }
2432
2433
EmitSuperConstructorCall(Call * expr)2434 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
2435 SuperCallReference* super_call_ref =
2436 expr->expression()->AsSuperCallReference();
2437 DCHECK_NOT_NULL(super_call_ref);
2438
2439 // Push the super constructor target on the stack (may be null,
2440 // but the Construct builtin can deal with that properly).
2441 VisitForAccumulatorValue(super_call_ref->this_function_var());
2442 __ AssertFunction(result_register());
2443 __ mov(result_register(),
2444 FieldOperand(result_register(), HeapObject::kMapOffset));
2445 PushOperand(FieldOperand(result_register(), Map::kPrototypeOffset));
2446
2447 // Push the arguments ("left-to-right") on the stack.
2448 ZoneList<Expression*>* args = expr->arguments();
2449 int arg_count = args->length();
2450 for (int i = 0; i < arg_count; i++) {
2451 VisitForStackValue(args->at(i));
2452 }
2453
2454 // Call the construct call builtin that handles allocation and
2455 // constructor invocation.
2456 SetConstructCallPosition(expr);
2457
2458 // Load new target into edx.
2459 VisitForAccumulatorValue(super_call_ref->new_target_var());
2460 __ mov(edx, result_register());
2461
2462 // Load function and argument count into edi and eax.
2463 __ Move(eax, Immediate(arg_count));
2464 __ mov(edi, Operand(esp, arg_count * kPointerSize));
2465
2466 __ Call(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
2467 OperandStackDepthDecrement(arg_count + 1);
2468
2469 RecordJSReturnSite(expr);
2470 RestoreContext();
2471 context()->Plug(eax);
2472 }
2473
2474
EmitIsSmi(CallRuntime * expr)2475 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2476 ZoneList<Expression*>* args = expr->arguments();
2477 DCHECK(args->length() == 1);
2478
2479 VisitForAccumulatorValue(args->at(0));
2480
2481 Label materialize_true, materialize_false;
2482 Label* if_true = NULL;
2483 Label* if_false = NULL;
2484 Label* fall_through = NULL;
2485 context()->PrepareTest(&materialize_true, &materialize_false,
2486 &if_true, &if_false, &fall_through);
2487
2488 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2489 __ test(eax, Immediate(kSmiTagMask));
2490 Split(zero, if_true, if_false, fall_through);
2491
2492 context()->Plug(if_true, if_false);
2493 }
2494
2495
EmitIsJSReceiver(CallRuntime * expr)2496 void FullCodeGenerator::EmitIsJSReceiver(CallRuntime* expr) {
2497 ZoneList<Expression*>* args = expr->arguments();
2498 DCHECK(args->length() == 1);
2499
2500 VisitForAccumulatorValue(args->at(0));
2501
2502 Label materialize_true, materialize_false;
2503 Label* if_true = NULL;
2504 Label* if_false = NULL;
2505 Label* fall_through = NULL;
2506 context()->PrepareTest(&materialize_true, &materialize_false,
2507 &if_true, &if_false, &fall_through);
2508
2509 __ JumpIfSmi(eax, if_false);
2510 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ebx);
2511 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2512 Split(above_equal, if_true, if_false, fall_through);
2513
2514 context()->Plug(if_true, if_false);
2515 }
2516
2517
EmitIsArray(CallRuntime * expr)2518 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2519 ZoneList<Expression*>* args = expr->arguments();
2520 DCHECK(args->length() == 1);
2521
2522 VisitForAccumulatorValue(args->at(0));
2523
2524 Label materialize_true, materialize_false;
2525 Label* if_true = NULL;
2526 Label* if_false = NULL;
2527 Label* fall_through = NULL;
2528 context()->PrepareTest(&materialize_true, &materialize_false,
2529 &if_true, &if_false, &fall_through);
2530
2531 __ JumpIfSmi(eax, if_false);
2532 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
2533 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2534 Split(equal, if_true, if_false, fall_through);
2535
2536 context()->Plug(if_true, if_false);
2537 }
2538
2539
EmitIsTypedArray(CallRuntime * expr)2540 void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) {
2541 ZoneList<Expression*>* args = expr->arguments();
2542 DCHECK(args->length() == 1);
2543
2544 VisitForAccumulatorValue(args->at(0));
2545
2546 Label materialize_true, materialize_false;
2547 Label* if_true = NULL;
2548 Label* if_false = NULL;
2549 Label* fall_through = NULL;
2550 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
2551 &if_false, &fall_through);
2552
2553 __ JumpIfSmi(eax, if_false);
2554 __ CmpObjectType(eax, JS_TYPED_ARRAY_TYPE, ebx);
2555 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2556 Split(equal, if_true, if_false, fall_through);
2557
2558 context()->Plug(if_true, if_false);
2559 }
2560
2561
EmitIsRegExp(CallRuntime * expr)2562 void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2563 ZoneList<Expression*>* args = expr->arguments();
2564 DCHECK(args->length() == 1);
2565
2566 VisitForAccumulatorValue(args->at(0));
2567
2568 Label materialize_true, materialize_false;
2569 Label* if_true = NULL;
2570 Label* if_false = NULL;
2571 Label* fall_through = NULL;
2572 context()->PrepareTest(&materialize_true, &materialize_false,
2573 &if_true, &if_false, &fall_through);
2574
2575 __ JumpIfSmi(eax, if_false);
2576 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
2577 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2578 Split(equal, if_true, if_false, fall_through);
2579
2580 context()->Plug(if_true, if_false);
2581 }
2582
2583
EmitIsJSProxy(CallRuntime * expr)2584 void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
2585 ZoneList<Expression*>* args = expr->arguments();
2586 DCHECK(args->length() == 1);
2587
2588 VisitForAccumulatorValue(args->at(0));
2589
2590 Label materialize_true, materialize_false;
2591 Label* if_true = NULL;
2592 Label* if_false = NULL;
2593 Label* fall_through = NULL;
2594 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
2595 &if_false, &fall_through);
2596
2597 __ JumpIfSmi(eax, if_false);
2598 __ CmpObjectType(eax, JS_PROXY_TYPE, ebx);
2599 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2600 Split(equal, if_true, if_false, fall_through);
2601
2602 context()->Plug(if_true, if_false);
2603 }
2604
2605
EmitClassOf(CallRuntime * expr)2606 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
2607 ZoneList<Expression*>* args = expr->arguments();
2608 DCHECK(args->length() == 1);
2609 Label done, null, function, non_function_constructor;
2610
2611 VisitForAccumulatorValue(args->at(0));
2612
2613 // If the object is not a JSReceiver, we return null.
2614 __ JumpIfSmi(eax, &null, Label::kNear);
2615 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2616 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, eax);
2617 __ j(below, &null, Label::kNear);
2618
2619 // Return 'Function' for JSFunction and JSBoundFunction objects.
2620 __ CmpInstanceType(eax, FIRST_FUNCTION_TYPE);
2621 STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE);
2622 __ j(above_equal, &function, Label::kNear);
2623
2624 // Check if the constructor in the map is a JS function.
2625 __ GetMapConstructor(eax, eax, ebx);
2626 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
2627 __ j(not_equal, &non_function_constructor, Label::kNear);
2628
2629 // eax now contains the constructor function. Grab the
2630 // instance class name from there.
2631 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2632 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2633 __ jmp(&done, Label::kNear);
2634
2635 // Non-JS objects have class null.
2636 __ bind(&null);
2637 __ mov(eax, isolate()->factory()->null_value());
2638 __ jmp(&done, Label::kNear);
2639
2640 // Functions have class 'Function'.
2641 __ bind(&function);
2642 __ mov(eax, isolate()->factory()->Function_string());
2643 __ jmp(&done, Label::kNear);
2644
2645 // Objects with a non-function constructor have class 'Object'.
2646 __ bind(&non_function_constructor);
2647 __ mov(eax, isolate()->factory()->Object_string());
2648
2649 // All done.
2650 __ bind(&done);
2651
2652 context()->Plug(eax);
2653 }
2654
2655
EmitStringCharCodeAt(CallRuntime * expr)2656 void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
2657 ZoneList<Expression*>* args = expr->arguments();
2658 DCHECK(args->length() == 2);
2659
2660 VisitForStackValue(args->at(0));
2661 VisitForAccumulatorValue(args->at(1));
2662
2663 Register object = ebx;
2664 Register index = eax;
2665 Register result = edx;
2666
2667 PopOperand(object);
2668
2669 Label need_conversion;
2670 Label index_out_of_range;
2671 Label done;
2672 StringCharCodeAtGenerator generator(object, index, result, &need_conversion,
2673 &need_conversion, &index_out_of_range);
2674 generator.GenerateFast(masm_);
2675 __ jmp(&done);
2676
2677 __ bind(&index_out_of_range);
2678 // When the index is out of range, the spec requires us to return
2679 // NaN.
2680 __ Move(result, Immediate(isolate()->factory()->nan_value()));
2681 __ jmp(&done);
2682
2683 __ bind(&need_conversion);
2684 // Move the undefined value into the result register, which will
2685 // trigger conversion.
2686 __ Move(result, Immediate(isolate()->factory()->undefined_value()));
2687 __ jmp(&done);
2688
2689 NopRuntimeCallHelper call_helper;
2690 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
2691
2692 __ bind(&done);
2693 context()->Plug(result);
2694 }
2695
2696
EmitCall(CallRuntime * expr)2697 void FullCodeGenerator::EmitCall(CallRuntime* expr) {
2698 ZoneList<Expression*>* args = expr->arguments();
2699 DCHECK_LE(2, args->length());
2700 // Push target, receiver and arguments onto the stack.
2701 for (Expression* const arg : *args) {
2702 VisitForStackValue(arg);
2703 }
2704 PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
2705 // Move target to edi.
2706 int const argc = args->length() - 2;
2707 __ mov(edi, Operand(esp, (argc + 1) * kPointerSize));
2708 // Call the target.
2709 __ mov(eax, Immediate(argc));
2710 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
2711 OperandStackDepthDecrement(argc + 1);
2712 RestoreContext();
2713 // Discard the function left on TOS.
2714 context()->DropAndPlug(1, eax);
2715 }
2716
EmitGetSuperConstructor(CallRuntime * expr)2717 void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) {
2718 ZoneList<Expression*>* args = expr->arguments();
2719 DCHECK_EQ(1, args->length());
2720 VisitForAccumulatorValue(args->at(0));
2721 __ AssertFunction(eax);
2722 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
2723 __ mov(eax, FieldOperand(eax, Map::kPrototypeOffset));
2724 context()->Plug(eax);
2725 }
2726
EmitDebugIsActive(CallRuntime * expr)2727 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
2728 DCHECK(expr->arguments()->length() == 0);
2729 ExternalReference debug_is_active =
2730 ExternalReference::debug_is_active_address(isolate());
2731 __ movzx_b(eax, Operand::StaticVariable(debug_is_active));
2732 __ SmiTag(eax);
2733 context()->Plug(eax);
2734 }
2735
2736
EmitCreateIterResultObject(CallRuntime * expr)2737 void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
2738 ZoneList<Expression*>* args = expr->arguments();
2739 DCHECK_EQ(2, args->length());
2740 VisitForStackValue(args->at(0));
2741 VisitForStackValue(args->at(1));
2742
2743 Label runtime, done;
2744
2745 __ Allocate(JSIteratorResult::kSize, eax, ecx, edx, &runtime,
2746 NO_ALLOCATION_FLAGS);
2747 __ mov(ebx, NativeContextOperand());
2748 __ mov(ebx, ContextOperand(ebx, Context::ITERATOR_RESULT_MAP_INDEX));
2749 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
2750 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
2751 isolate()->factory()->empty_fixed_array());
2752 __ mov(FieldOperand(eax, JSObject::kElementsOffset),
2753 isolate()->factory()->empty_fixed_array());
2754 __ pop(FieldOperand(eax, JSIteratorResult::kDoneOffset));
2755 __ pop(FieldOperand(eax, JSIteratorResult::kValueOffset));
2756 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
2757 __ jmp(&done, Label::kNear);
2758
2759 __ bind(&runtime);
2760 CallRuntimeWithOperands(Runtime::kCreateIterResultObject);
2761
2762 __ bind(&done);
2763 context()->Plug(eax);
2764 }
2765
2766
EmitLoadJSRuntimeFunction(CallRuntime * expr)2767 void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
2768 // Push function.
2769 __ LoadGlobalFunction(expr->context_index(), eax);
2770 PushOperand(eax);
2771
2772 // Push undefined as receiver.
2773 PushOperand(isolate()->factory()->undefined_value());
2774 }
2775
2776
EmitCallJSRuntimeFunction(CallRuntime * expr)2777 void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) {
2778 ZoneList<Expression*>* args = expr->arguments();
2779 int arg_count = args->length();
2780
2781 SetCallPosition(expr);
2782 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2783 __ Set(eax, arg_count);
2784 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined),
2785 RelocInfo::CODE_TARGET);
2786 OperandStackDepthDecrement(arg_count + 1);
2787 RestoreContext();
2788 }
2789
2790
VisitUnaryOperation(UnaryOperation * expr)2791 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
2792 switch (expr->op()) {
2793 case Token::DELETE: {
2794 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
2795 Property* property = expr->expression()->AsProperty();
2796 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2797
2798 if (property != NULL) {
2799 VisitForStackValue(property->obj());
2800 VisitForStackValue(property->key());
2801 CallRuntimeWithOperands(is_strict(language_mode())
2802 ? Runtime::kDeleteProperty_Strict
2803 : Runtime::kDeleteProperty_Sloppy);
2804 context()->Plug(eax);
2805 } else if (proxy != NULL) {
2806 Variable* var = proxy->var();
2807 // Delete of an unqualified identifier is disallowed in strict mode but
2808 // "delete this" is allowed.
2809 bool is_this = var->is_this();
2810 DCHECK(is_sloppy(language_mode()) || is_this);
2811 if (var->IsUnallocated()) {
2812 __ mov(eax, NativeContextOperand());
2813 __ push(ContextOperand(eax, Context::EXTENSION_INDEX));
2814 __ push(Immediate(var->name()));
2815 __ CallRuntime(Runtime::kDeleteProperty_Sloppy);
2816 context()->Plug(eax);
2817 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
2818 // Result of deleting non-global variables is false. 'this' is
2819 // not really a variable, though we implement it as one. The
2820 // subexpression does not have side effects.
2821 context()->Plug(is_this);
2822 } else {
2823 // Non-global variable. Call the runtime to try to delete from the
2824 // context where the variable was introduced.
2825 __ Push(var->name());
2826 __ CallRuntime(Runtime::kDeleteLookupSlot);
2827 context()->Plug(eax);
2828 }
2829 } else {
2830 // Result of deleting non-property, non-variable reference is true.
2831 // The subexpression may have side effects.
2832 VisitForEffect(expr->expression());
2833 context()->Plug(true);
2834 }
2835 break;
2836 }
2837
2838 case Token::VOID: {
2839 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
2840 VisitForEffect(expr->expression());
2841 context()->Plug(isolate()->factory()->undefined_value());
2842 break;
2843 }
2844
2845 case Token::NOT: {
2846 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
2847 if (context()->IsEffect()) {
2848 // Unary NOT has no side effects so it's only necessary to visit the
2849 // subexpression. Match the optimizing compiler by not branching.
2850 VisitForEffect(expr->expression());
2851 } else if (context()->IsTest()) {
2852 const TestContext* test = TestContext::cast(context());
2853 // The labels are swapped for the recursive call.
2854 VisitForControl(expr->expression(),
2855 test->false_label(),
2856 test->true_label(),
2857 test->fall_through());
2858 context()->Plug(test->true_label(), test->false_label());
2859 } else {
2860 // We handle value contexts explicitly rather than simply visiting
2861 // for control and plugging the control flow into the context,
2862 // because we need to prepare a pair of extra administrative AST ids
2863 // for the optimizing compiler.
2864 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
2865 Label materialize_true, materialize_false, done;
2866 VisitForControl(expr->expression(),
2867 &materialize_false,
2868 &materialize_true,
2869 &materialize_true);
2870 if (!context()->IsAccumulatorValue()) OperandStackDepthIncrement(1);
2871 __ bind(&materialize_true);
2872 PrepareForBailoutForId(expr->MaterializeTrueId(),
2873 BailoutState::NO_REGISTERS);
2874 if (context()->IsAccumulatorValue()) {
2875 __ mov(eax, isolate()->factory()->true_value());
2876 } else {
2877 __ Push(isolate()->factory()->true_value());
2878 }
2879 __ jmp(&done, Label::kNear);
2880 __ bind(&materialize_false);
2881 PrepareForBailoutForId(expr->MaterializeFalseId(),
2882 BailoutState::NO_REGISTERS);
2883 if (context()->IsAccumulatorValue()) {
2884 __ mov(eax, isolate()->factory()->false_value());
2885 } else {
2886 __ Push(isolate()->factory()->false_value());
2887 }
2888 __ bind(&done);
2889 }
2890 break;
2891 }
2892
2893 case Token::TYPEOF: {
2894 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
2895 {
2896 AccumulatorValueContext context(this);
2897 VisitForTypeofValue(expr->expression());
2898 }
2899 __ mov(ebx, eax);
2900 __ Call(isolate()->builtins()->Typeof(), RelocInfo::CODE_TARGET);
2901 context()->Plug(eax);
2902 break;
2903 }
2904
2905 default:
2906 UNREACHABLE();
2907 }
2908 }
2909
2910
VisitCountOperation(CountOperation * expr)2911 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
2912 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
2913
2914 Comment cmnt(masm_, "[ CountOperation");
2915
2916 Property* prop = expr->expression()->AsProperty();
2917 LhsKind assign_type = Property::GetAssignType(prop);
2918
2919 // Evaluate expression and get value.
2920 if (assign_type == VARIABLE) {
2921 DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
2922 AccumulatorValueContext context(this);
2923 EmitVariableLoad(expr->expression()->AsVariableProxy());
2924 } else {
2925 // Reserve space for result of postfix operation.
2926 if (expr->is_postfix() && !context()->IsEffect()) {
2927 PushOperand(Smi::kZero);
2928 }
2929 switch (assign_type) {
2930 case NAMED_PROPERTY: {
2931 // Put the object both on the stack and in the register.
2932 VisitForStackValue(prop->obj());
2933 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
2934 EmitNamedPropertyLoad(prop);
2935 break;
2936 }
2937
2938 case NAMED_SUPER_PROPERTY: {
2939 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2940 VisitForAccumulatorValue(
2941 prop->obj()->AsSuperPropertyReference()->home_object());
2942 PushOperand(result_register());
2943 PushOperand(MemOperand(esp, kPointerSize));
2944 PushOperand(result_register());
2945 EmitNamedSuperPropertyLoad(prop);
2946 break;
2947 }
2948
2949 case KEYED_SUPER_PROPERTY: {
2950 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2951 VisitForStackValue(
2952 prop->obj()->AsSuperPropertyReference()->home_object());
2953 VisitForAccumulatorValue(prop->key());
2954 PushOperand(result_register());
2955 PushOperand(MemOperand(esp, 2 * kPointerSize));
2956 PushOperand(MemOperand(esp, 2 * kPointerSize));
2957 PushOperand(result_register());
2958 EmitKeyedSuperPropertyLoad(prop);
2959 break;
2960 }
2961
2962 case KEYED_PROPERTY: {
2963 VisitForStackValue(prop->obj());
2964 VisitForStackValue(prop->key());
2965 __ mov(LoadDescriptor::ReceiverRegister(),
2966 Operand(esp, kPointerSize)); // Object.
2967 __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0)); // Key.
2968 EmitKeyedPropertyLoad(prop);
2969 break;
2970 }
2971
2972 case VARIABLE:
2973 UNREACHABLE();
2974 }
2975 }
2976
2977 // We need a second deoptimization point after loading the value
2978 // in case evaluating the property load my have a side effect.
2979 if (assign_type == VARIABLE) {
2980 PrepareForBailout(expr->expression(), BailoutState::TOS_REGISTER);
2981 } else {
2982 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
2983 }
2984
2985 // Inline smi case if we are in a loop.
2986 Label done, stub_call;
2987 JumpPatchSite patch_site(masm_);
2988 if (ShouldInlineSmiCase(expr->op())) {
2989 Label slow;
2990 patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
2991
2992 // Save result for postfix expressions.
2993 if (expr->is_postfix()) {
2994 if (!context()->IsEffect()) {
2995 // Save the result on the stack. If we have a named or keyed property
2996 // we store the result under the receiver that is currently on top
2997 // of the stack.
2998 switch (assign_type) {
2999 case VARIABLE:
3000 __ push(eax);
3001 break;
3002 case NAMED_PROPERTY:
3003 __ mov(Operand(esp, kPointerSize), eax);
3004 break;
3005 case NAMED_SUPER_PROPERTY:
3006 __ mov(Operand(esp, 2 * kPointerSize), eax);
3007 break;
3008 case KEYED_PROPERTY:
3009 __ mov(Operand(esp, 2 * kPointerSize), eax);
3010 break;
3011 case KEYED_SUPER_PROPERTY:
3012 __ mov(Operand(esp, 3 * kPointerSize), eax);
3013 break;
3014 }
3015 }
3016 }
3017
3018 if (expr->op() == Token::INC) {
3019 __ add(eax, Immediate(Smi::FromInt(1)));
3020 } else {
3021 __ sub(eax, Immediate(Smi::FromInt(1)));
3022 }
3023 __ j(no_overflow, &done, Label::kNear);
3024 // Call stub. Undo operation first.
3025 if (expr->op() == Token::INC) {
3026 __ sub(eax, Immediate(Smi::FromInt(1)));
3027 } else {
3028 __ add(eax, Immediate(Smi::FromInt(1)));
3029 }
3030 __ jmp(&stub_call, Label::kNear);
3031 __ bind(&slow);
3032 }
3033
3034 // Convert old value into a number.
3035 __ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
3036 RestoreContext();
3037 PrepareForBailoutForId(expr->ToNumberId(), BailoutState::TOS_REGISTER);
3038
3039 // Save result for postfix expressions.
3040 if (expr->is_postfix()) {
3041 if (!context()->IsEffect()) {
3042 // Save the result on the stack. If we have a named or keyed property
3043 // we store the result under the receiver that is currently on top
3044 // of the stack.
3045 switch (assign_type) {
3046 case VARIABLE:
3047 PushOperand(eax);
3048 break;
3049 case NAMED_PROPERTY:
3050 __ mov(Operand(esp, kPointerSize), eax);
3051 break;
3052 case NAMED_SUPER_PROPERTY:
3053 __ mov(Operand(esp, 2 * kPointerSize), eax);
3054 break;
3055 case KEYED_PROPERTY:
3056 __ mov(Operand(esp, 2 * kPointerSize), eax);
3057 break;
3058 case KEYED_SUPER_PROPERTY:
3059 __ mov(Operand(esp, 3 * kPointerSize), eax);
3060 break;
3061 }
3062 }
3063 }
3064
3065 SetExpressionPosition(expr);
3066
3067 // Call stub for +1/-1.
3068 __ bind(&stub_call);
3069 __ mov(edx, eax);
3070 __ mov(eax, Immediate(Smi::FromInt(1)));
3071 Handle<Code> code =
3072 CodeFactory::BinaryOpIC(isolate(), expr->binary_op()).code();
3073 CallIC(code, expr->CountBinOpFeedbackId());
3074 patch_site.EmitPatchInfo();
3075 __ bind(&done);
3076
3077 // Store the value returned in eax.
3078 switch (assign_type) {
3079 case VARIABLE: {
3080 VariableProxy* proxy = expr->expression()->AsVariableProxy();
3081 if (expr->is_postfix()) {
3082 // Perform the assignment as if via '='.
3083 { EffectContext context(this);
3084 EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
3085 proxy->hole_check_mode());
3086 PrepareForBailoutForId(expr->AssignmentId(),
3087 BailoutState::TOS_REGISTER);
3088 context.Plug(eax);
3089 }
3090 // For all contexts except EffectContext We have the result on
3091 // top of the stack.
3092 if (!context()->IsEffect()) {
3093 context()->PlugTOS();
3094 }
3095 } else {
3096 // Perform the assignment as if via '='.
3097 EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
3098 proxy->hole_check_mode());
3099 PrepareForBailoutForId(expr->AssignmentId(),
3100 BailoutState::TOS_REGISTER);
3101 context()->Plug(eax);
3102 }
3103 break;
3104 }
3105 case NAMED_PROPERTY: {
3106 PopOperand(StoreDescriptor::ReceiverRegister());
3107 CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value());
3108 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
3109 if (expr->is_postfix()) {
3110 if (!context()->IsEffect()) {
3111 context()->PlugTOS();
3112 }
3113 } else {
3114 context()->Plug(eax);
3115 }
3116 break;
3117 }
3118 case NAMED_SUPER_PROPERTY: {
3119 EmitNamedSuperPropertyStore(prop);
3120 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
3121 if (expr->is_postfix()) {
3122 if (!context()->IsEffect()) {
3123 context()->PlugTOS();
3124 }
3125 } else {
3126 context()->Plug(eax);
3127 }
3128 break;
3129 }
3130 case KEYED_SUPER_PROPERTY: {
3131 EmitKeyedSuperPropertyStore(prop);
3132 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
3133 if (expr->is_postfix()) {
3134 if (!context()->IsEffect()) {
3135 context()->PlugTOS();
3136 }
3137 } else {
3138 context()->Plug(eax);
3139 }
3140 break;
3141 }
3142 case KEYED_PROPERTY: {
3143 PopOperand(StoreDescriptor::NameRegister());
3144 PopOperand(StoreDescriptor::ReceiverRegister());
3145 CallKeyedStoreIC(expr->CountSlot());
3146 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
3147 if (expr->is_postfix()) {
3148 // Result is on the stack
3149 if (!context()->IsEffect()) {
3150 context()->PlugTOS();
3151 }
3152 } else {
3153 context()->Plug(eax);
3154 }
3155 break;
3156 }
3157 }
3158 }
3159
3160
EmitLiteralCompareTypeof(Expression * expr,Expression * sub_expr,Handle<String> check)3161 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
3162 Expression* sub_expr,
3163 Handle<String> check) {
3164 Label materialize_true, materialize_false;
3165 Label* if_true = NULL;
3166 Label* if_false = NULL;
3167 Label* fall_through = NULL;
3168 context()->PrepareTest(&materialize_true, &materialize_false,
3169 &if_true, &if_false, &fall_through);
3170
3171 { AccumulatorValueContext context(this);
3172 VisitForTypeofValue(sub_expr);
3173 }
3174 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3175
3176 Factory* factory = isolate()->factory();
3177 if (String::Equals(check, factory->number_string())) {
3178 __ JumpIfSmi(eax, if_true);
3179 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3180 isolate()->factory()->heap_number_map());
3181 Split(equal, if_true, if_false, fall_through);
3182 } else if (String::Equals(check, factory->string_string())) {
3183 __ JumpIfSmi(eax, if_false);
3184 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
3185 Split(below, if_true, if_false, fall_through);
3186 } else if (String::Equals(check, factory->symbol_string())) {
3187 __ JumpIfSmi(eax, if_false);
3188 __ CmpObjectType(eax, SYMBOL_TYPE, edx);
3189 Split(equal, if_true, if_false, fall_through);
3190 } else if (String::Equals(check, factory->boolean_string())) {
3191 __ cmp(eax, isolate()->factory()->true_value());
3192 __ j(equal, if_true);
3193 __ cmp(eax, isolate()->factory()->false_value());
3194 Split(equal, if_true, if_false, fall_through);
3195 } else if (String::Equals(check, factory->undefined_string())) {
3196 __ cmp(eax, isolate()->factory()->null_value());
3197 __ j(equal, if_false);
3198 __ JumpIfSmi(eax, if_false);
3199 // Check for undetectable objects => true.
3200 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3201 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
3202 Immediate(1 << Map::kIsUndetectable));
3203 Split(not_zero, if_true, if_false, fall_through);
3204 } else if (String::Equals(check, factory->function_string())) {
3205 __ JumpIfSmi(eax, if_false);
3206 // Check for callable and not undetectable objects => true.
3207 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3208 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3209 __ and_(ecx, (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable));
3210 __ cmp(ecx, 1 << Map::kIsCallable);
3211 Split(equal, if_true, if_false, fall_through);
3212 } else if (String::Equals(check, factory->object_string())) {
3213 __ JumpIfSmi(eax, if_false);
3214 __ cmp(eax, isolate()->factory()->null_value());
3215 __ j(equal, if_true);
3216 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
3217 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, edx);
3218 __ j(below, if_false);
3219 // Check for callable or undetectable objects => false.
3220 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
3221 Immediate((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)));
3222 Split(zero, if_true, if_false, fall_through);
3223 // clang-format off
3224 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
3225 } else if (String::Equals(check, factory->type##_string())) { \
3226 __ JumpIfSmi(eax, if_false); \
3227 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), \
3228 isolate()->factory()->type##_map()); \
3229 Split(equal, if_true, if_false, fall_through);
3230 SIMD128_TYPES(SIMD128_TYPE)
3231 #undef SIMD128_TYPE
3232 // clang-format on
3233 } else {
3234 if (if_false != fall_through) __ jmp(if_false);
3235 }
3236 context()->Plug(if_true, if_false);
3237 }
3238
3239
VisitCompareOperation(CompareOperation * expr)3240 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3241 Comment cmnt(masm_, "[ CompareOperation");
3242
3243 // First we try a fast inlined version of the compare when one of
3244 // the operands is a literal.
3245 if (TryLiteralCompare(expr)) return;
3246
3247 // Always perform the comparison for its control flow. Pack the result
3248 // into the expression's context after the comparison is performed.
3249 Label materialize_true, materialize_false;
3250 Label* if_true = NULL;
3251 Label* if_false = NULL;
3252 Label* fall_through = NULL;
3253 context()->PrepareTest(&materialize_true, &materialize_false,
3254 &if_true, &if_false, &fall_through);
3255
3256 Token::Value op = expr->op();
3257 VisitForStackValue(expr->left());
3258 switch (op) {
3259 case Token::IN:
3260 VisitForStackValue(expr->right());
3261 SetExpressionPosition(expr);
3262 EmitHasProperty();
3263 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3264 __ cmp(eax, isolate()->factory()->true_value());
3265 Split(equal, if_true, if_false, fall_through);
3266 break;
3267
3268 case Token::INSTANCEOF: {
3269 VisitForAccumulatorValue(expr->right());
3270 SetExpressionPosition(expr);
3271 PopOperand(edx);
3272 __ Call(isolate()->builtins()->InstanceOf(), RelocInfo::CODE_TARGET);
3273 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3274 __ cmp(eax, isolate()->factory()->true_value());
3275 Split(equal, if_true, if_false, fall_through);
3276 break;
3277 }
3278
3279 default: {
3280 VisitForAccumulatorValue(expr->right());
3281 SetExpressionPosition(expr);
3282 Condition cc = CompareIC::ComputeCondition(op);
3283 PopOperand(edx);
3284
3285 bool inline_smi_code = ShouldInlineSmiCase(op);
3286 JumpPatchSite patch_site(masm_);
3287 if (inline_smi_code) {
3288 Label slow_case;
3289 __ mov(ecx, edx);
3290 __ or_(ecx, eax);
3291 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
3292 __ cmp(edx, eax);
3293 Split(cc, if_true, if_false, NULL);
3294 __ bind(&slow_case);
3295 }
3296
3297 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
3298 CallIC(ic, expr->CompareOperationFeedbackId());
3299 patch_site.EmitPatchInfo();
3300
3301 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3302 __ test(eax, eax);
3303 Split(cc, if_true, if_false, fall_through);
3304 }
3305 }
3306
3307 // Convert the result of the comparison into one expected for this
3308 // expression's context.
3309 context()->Plug(if_true, if_false);
3310 }
3311
3312
EmitLiteralCompareNil(CompareOperation * expr,Expression * sub_expr,NilValue nil)3313 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
3314 Expression* sub_expr,
3315 NilValue nil) {
3316 Label materialize_true, materialize_false;
3317 Label* if_true = NULL;
3318 Label* if_false = NULL;
3319 Label* fall_through = NULL;
3320 context()->PrepareTest(&materialize_true, &materialize_false,
3321 &if_true, &if_false, &fall_through);
3322
3323 VisitForAccumulatorValue(sub_expr);
3324 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3325
3326 Handle<Object> nil_value = nil == kNullValue
3327 ? isolate()->factory()->null_value()
3328 : isolate()->factory()->undefined_value();
3329 if (expr->op() == Token::EQ_STRICT) {
3330 __ cmp(eax, nil_value);
3331 Split(equal, if_true, if_false, fall_through);
3332 } else {
3333 __ JumpIfSmi(eax, if_false);
3334 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
3335 __ test_b(FieldOperand(eax, Map::kBitFieldOffset),
3336 Immediate(1 << Map::kIsUndetectable));
3337 Split(not_zero, if_true, if_false, fall_through);
3338 }
3339 context()->Plug(if_true, if_false);
3340 }
3341
3342
result_register()3343 Register FullCodeGenerator::result_register() {
3344 return eax;
3345 }
3346
3347
context_register()3348 Register FullCodeGenerator::context_register() {
3349 return esi;
3350 }
3351
LoadFromFrameField(int frame_offset,Register value)3352 void FullCodeGenerator::LoadFromFrameField(int frame_offset, Register value) {
3353 DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3354 __ mov(value, Operand(ebp, frame_offset));
3355 }
3356
StoreToFrameField(int frame_offset,Register value)3357 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
3358 DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3359 __ mov(Operand(ebp, frame_offset), value);
3360 }
3361
3362
LoadContextField(Register dst,int context_index)3363 void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
3364 __ mov(dst, ContextOperand(esi, context_index));
3365 }
3366
3367
PushFunctionArgumentForContextAllocation()3368 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
3369 DeclarationScope* closure_scope = scope()->GetClosureScope();
3370 if (closure_scope->is_script_scope() ||
3371 closure_scope->is_module_scope()) {
3372 // Contexts nested in the native context have a canonical empty function
3373 // as their closure, not the anonymous closure containing the global
3374 // code.
3375 __ mov(eax, NativeContextOperand());
3376 PushOperand(ContextOperand(eax, Context::CLOSURE_INDEX));
3377 } else if (closure_scope->is_eval_scope()) {
3378 // Contexts nested inside eval code have the same closure as the context
3379 // calling eval, not the anonymous closure containing the eval code.
3380 // Fetch it from the context.
3381 PushOperand(ContextOperand(esi, Context::CLOSURE_INDEX));
3382 } else {
3383 DCHECK(closure_scope->is_function_scope());
3384 PushOperand(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3385 }
3386 }
3387
3388
3389 // ----------------------------------------------------------------------------
3390 // Non-local control flow support.
3391
EnterFinallyBlock()3392 void FullCodeGenerator::EnterFinallyBlock() {
3393 // Store pending message while executing finally block.
3394 ExternalReference pending_message_obj =
3395 ExternalReference::address_of_pending_message_obj(isolate());
3396 __ mov(edx, Operand::StaticVariable(pending_message_obj));
3397 PushOperand(edx);
3398
3399 ClearPendingMessage();
3400 }
3401
3402
ExitFinallyBlock()3403 void FullCodeGenerator::ExitFinallyBlock() {
3404 DCHECK(!result_register().is(edx));
3405 // Restore pending message from stack.
3406 PopOperand(edx);
3407 ExternalReference pending_message_obj =
3408 ExternalReference::address_of_pending_message_obj(isolate());
3409 __ mov(Operand::StaticVariable(pending_message_obj), edx);
3410 }
3411
3412
ClearPendingMessage()3413 void FullCodeGenerator::ClearPendingMessage() {
3414 DCHECK(!result_register().is(edx));
3415 ExternalReference pending_message_obj =
3416 ExternalReference::address_of_pending_message_obj(isolate());
3417 __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
3418 __ mov(Operand::StaticVariable(pending_message_obj), edx);
3419 }
3420
3421
EmitCommands()3422 void FullCodeGenerator::DeferredCommands::EmitCommands() {
3423 DCHECK(!result_register().is(edx));
3424 __ Pop(result_register()); // Restore the accumulator.
3425 __ Pop(edx); // Get the token.
3426 for (DeferredCommand cmd : commands_) {
3427 Label skip;
3428 __ cmp(edx, Immediate(Smi::FromInt(cmd.token)));
3429 __ j(not_equal, &skip);
3430 switch (cmd.command) {
3431 case kReturn:
3432 codegen_->EmitUnwindAndReturn();
3433 break;
3434 case kThrow:
3435 __ Push(result_register());
3436 __ CallRuntime(Runtime::kReThrow);
3437 break;
3438 case kContinue:
3439 codegen_->EmitContinue(cmd.target);
3440 break;
3441 case kBreak:
3442 codegen_->EmitBreak(cmd.target);
3443 break;
3444 }
3445 __ bind(&skip);
3446 }
3447 }
3448
3449 #undef __
3450
3451
3452 static const byte kJnsInstruction = 0x79;
3453 static const byte kJnsOffset = 0x11;
3454 static const byte kNopByteOne = 0x66;
3455 static const byte kNopByteTwo = 0x90;
3456 #ifdef DEBUG
3457 static const byte kCallInstruction = 0xe8;
3458 #endif
3459
3460
PatchAt(Code * unoptimized_code,Address pc,BackEdgeState target_state,Code * replacement_code)3461 void BackEdgeTable::PatchAt(Code* unoptimized_code,
3462 Address pc,
3463 BackEdgeState target_state,
3464 Code* replacement_code) {
3465 Address call_target_address = pc - kIntSize;
3466 Address jns_instr_address = call_target_address - 3;
3467 Address jns_offset_address = call_target_address - 2;
3468
3469 switch (target_state) {
3470 case INTERRUPT:
3471 // sub <profiling_counter>, <delta> ;; Not changed
3472 // jns ok
3473 // call <interrupt stub>
3474 // ok:
3475 *jns_instr_address = kJnsInstruction;
3476 *jns_offset_address = kJnsOffset;
3477 break;
3478 case ON_STACK_REPLACEMENT:
3479 // sub <profiling_counter>, <delta> ;; Not changed
3480 // nop
3481 // nop
3482 // call <on-stack replacment>
3483 // ok:
3484 *jns_instr_address = kNopByteOne;
3485 *jns_offset_address = kNopByteTwo;
3486 break;
3487 }
3488
3489 Assembler::set_target_address_at(unoptimized_code->GetIsolate(),
3490 call_target_address, unoptimized_code,
3491 replacement_code->entry());
3492 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
3493 unoptimized_code, call_target_address, replacement_code);
3494 }
3495
3496
GetBackEdgeState(Isolate * isolate,Code * unoptimized_code,Address pc)3497 BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
3498 Isolate* isolate,
3499 Code* unoptimized_code,
3500 Address pc) {
3501 Address call_target_address = pc - kIntSize;
3502 Address jns_instr_address = call_target_address - 3;
3503 DCHECK_EQ(kCallInstruction, *(call_target_address - 1));
3504
3505 if (*jns_instr_address == kJnsInstruction) {
3506 DCHECK_EQ(kJnsOffset, *(call_target_address - 2));
3507 DCHECK_EQ(isolate->builtins()->InterruptCheck()->entry(),
3508 Assembler::target_address_at(call_target_address,
3509 unoptimized_code));
3510 return INTERRUPT;
3511 }
3512
3513 DCHECK_EQ(kNopByteOne, *jns_instr_address);
3514 DCHECK_EQ(kNopByteTwo, *(call_target_address - 2));
3515
3516 DCHECK_EQ(
3517 isolate->builtins()->OnStackReplacement()->entry(),
3518 Assembler::target_address_at(call_target_address, unoptimized_code));
3519 return ON_STACK_REPLACEMENT;
3520 }
3521
3522
3523 } // namespace internal
3524 } // namespace v8
3525
3526 #endif // V8_TARGET_ARCH_X87
3527